'How to identify whether webp image is static or animated?

I am working on a project where a user can upload webp images. I know how to convert webp images into jpg/png, but am stuck on how to identify whether the webp image is static (non-animated) or animated.

I want to identify them because I use different commands for conversion:

Command for non-animated webp to jpg:

dwebp nonanimated.webp -o jpg.jpg

Command for animated webp to non-animated webp (takes 2nd frame):

webpmux -get frame 2 animated.webp -o nonanimated.webp

But I cannot find a single command that handle both cases.

I am using PHP on the server side, and HTML and Javascript for frontend.



Solution 1:[1]

After a lot of investigation i found that animated webp images always conatins some string, when open in a text editor and non animated images doesn't. The strings are ANMF and ANIM. I checked these string in all webp images which i have. So this is perfect for me. Here are some solutions in PHP, Javascript and Shell Script:

In PHP:

<?php
function isWebpAnimated($src){
    $webpContents = file_get_contents($src);
    $where = strpos($webpContents, "ANMF");
    if ($where !== FALSE){
        // animated
        $isAnimated = true;
    }
    else{
        // non animated
        $isAnimated = false;
    }
    return $isAnimated;
}
?>

In Javascript:

function isAnimatedGif(src) {
    var request = new XMLHttpRequest();
    request.open('GET', src, true);
    request.addEventListener('load', function () {
        if(request.response.indexOf("ANMF") != -1){
            // animated
            alert(true);
        }
        else{
            // non animated
            alert(false);
        }
    });
    request.send();
}

But In case of large images PHP and Javascript not working well, So best Solution is to use Shell Script, If you have Ubuntu.

In Shell Script:

echo $(grep -c "ANMF" ~/animated.webp)

return 0 if non animated, else non zero value for animated.

Solution 2:[2]

There are flags in Webp header, ANIMATION among others. Small function to check it:

function isWebpAnimated($fn){
  $result = false;
  $fh = fopen($fn, "rb"); 
  fseek($fh, 12);
  if(fread($fh, 4) === 'VP8X'){
    fseek($fh, 16);
    $myByte = fread($fh, 1);
    $result = ((ord($myByte) >> 1) & 1)?true:false;
  }
  fclose($fh);
  return $result;
}

ANIM and ANMF are from next chunk headers.

RIFF container specification

Solution 3:[3]

According Sven Liivak's isWebpAnimated()... there is a small bug.

fseek($fh, 16);

should be:

fseek($fh, 20);

Because postion 16 is the chunk_size position in VP8X. But we need the flag position which is at 20.

Fixed function:

function isWebpAnimated($fn){
  $result = false;
  $fh = fopen($fn, "rb"); 
  fseek($fh, 12);
  if(fread($fh, 4) === 'VP8X'){
    fseek($fh, 20);
    $myByte = fread($fh, 1);
    $result = ((ord($myByte) >> 1) & 1)?true:false;
  }
  fclose($fh);
  return $result;
}

Solution 4:[4]

This is my java code, it works for me.

static boolean isWebpAnimated(InputStream in) {
        boolean result = false;
        try {
            in.skip(12);
            byte[] buf = new byte[4];
            int i = in.read(buf);
            if ("VP8X".equals(new String(buf, 0, i))) {
                in.skip(12);
                result = (in.read(buf) == 4 && (buf[3] & 0x00000002) != 0);
            }
        } catch (Exception e) {
        } finally {
            try {
                in.close();
            } catch (Exception e) {
            }
        }
        return result;
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 HarisH Sharma
Solution 2
Solution 3 Hans-Jürgen Petrich
Solution 4 ccomangee