如何识别webp图片是静态图片还是动画图片?

How to identify whether webp image is static or animated?

我正在开发一个用户可以上传 webp 图片的项目。我知道如何将 webp 图像转换为 jpg/png,但我仍然不知道如何识别 webp 图像是静态(非动画)还是动画。

我想识别它们,因为我使用不同的命令进行转换:

非动画 webp 到 jpg 的命令:

dwebp nonanimated.webp -o jpg.jpg

动画 webp 到非动画 webp 的命令(需要第二帧):

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

但是我找不到一个命令可以处理这两种情况。

我在服务器端使用 PHP,在前端使用 HTML 和 Javascript。

经过大量调查,我发现动画 webp 图像总是包含一些字符串,当在文本编辑器中打开时,非动画图像则不会。字符串是 ANMFANIM。我在我拥有的所有 webp 图像中检查了这些字符串。所以这对我来说是完美的。以下是 PHPJavascriptShell Script 中的一些解决方案:

在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;
}
?>

在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();
}

但是如果大图像 PHPJavascript 效果不佳,那么最好的解决方案是使用 Shell Script,如果你有 Ubuntu.

在 Shell 脚本中:

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

return 如果非动画则为 0,否则为动画非零值。

Webp header、ANIMATION 等中有标志。检查它的小函数:

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 和 ANMF 来自下一个区块 headers.

RIFF container specification

根据Sven LiivakisWebpAnimated()...有一个小错误。

fseek($fh, 16);

应该是:

fseek($fh, 20);

因为位置 16VP8X 中的 chunk_size 位置。 但是我们需要 flag 位置,它位于 20.

固定函数:

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;
}

这是我的 java 代码,对我有用。

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;
    }