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

问题描述 投票:0回答:7

我正在做一个用户可以上传

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。

javascript php webp
7个回答
7
投票

经过大量调查,我发现动画

webp
图像总是包含一些字符串,当在文本编辑器中打开时,非动画图像则不会。字符串是
ANMF
ANIM
。我在我拥有的所有 webp 图像中检查了这些字符串。所以这对我来说是完美的。以下是
PHP
Javascript
Shell 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();
}

但是如果大图像

PHP
Javascript
效果不佳,那么最好的解决方案是使用
Shell Script
,如果你有
Ubuntu
.

在 Shell 脚本中:

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

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


6
投票

Webp 标头中有标志,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 来自下一个块头。

RIFF 容器规格


4
投票

根据Sven Liivak

isWebpAnimated()
...有一个小错误。

fseek($fh, 16);

应该是:

fseek($fh, 20);

因为位置

16
chunk_size
中的
VP8X
位置。 但是我们需要位于
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;
}

2
投票

这是我的 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;
    }

1
投票

修复@ccomangee 的解决方案。 一些静态 webp 图像会被检测为动画,并可能导致应用程序出现问题。

我提取了 webp 帧并保存为 webp 图像,并尝试通过检查 VP8X 签名来识别,它存在于给定位置,尽管它是静态图像。因此,如果有 VP8X,这并不意味着图像将具有多于一帧的动画效果。

我用我的解决方案尝试了几张图片,结果如下:

                             riff   webp  vp8*   anim
OK(anim-trans).webp:      [ RIFF | WEBP | VP8X | ANIM ]
Cuppy(static-trans).webp: [ RIFF | WEBP | VP8L | NA?  ]
glass(anim-solid).webp:   [ RIFF | WEBP | VP8X | ANIM ]
sunset(anim-trans).webp:  [ RIFF | WEBP | VP8X | ANIM ]
atom(anim_solid).webp:    [ RIFF | WEBP | VP8X | ANIM ]
spread(anim-trans).webp:  [ RIFF | WEBP | VP8X | ANIM ]
heart(static-trans).webp: [ RIFF | WEBP | VP8X | NA?  ] 
ludo(static-trans).webp:  [ RIFF | WEBP | VP8X | NA?  ]
scene(static_solid).webp: [ RIFF | WEBP | VP8  | NA?  ]

这里所有的图片都根据其类型命名。 anim-trans:动画图像包含透明度(alpha 通道支持) anim-solid:没有透明度的动画图像 static-trans 和 static-solid 是静态图像。

VP8L 是无损 webp,VP8X 包含扩展功能。 VP8肯定是静态图像。

如果 VP8X 存在,它可以是静态的或动画的,大多数图像将是动画的。

解决方案是

读取 4 个字节 -> 'RIFF' 跳过 4 个字节 读取 4 个字节 -> 'WEBP' 读取 4 个字节 -> 'VP8X' / 'VP8L' / 'VP8' 跳过 14 个字节 读取 4 个字节 -> 'ANIM'

Java代码:

 public static boolean check(File file) {
            boolean riff = false;
            boolean webp = false;
            boolean vp8x = false;
            boolean anim = false;
        try (InputStream in = new FileInputStream(file)) {

            byte[] buf = new byte[4];
            int i = in.read(buf); // 4
            
            if(buf[0] == 0x52 && buf[1] == 0x49 && buf[2]==0x46 && buf[3] == buf[2] )
                riff = true;

            in.skip(4); // ???? (8+)
            i = in.read(buf); // (12+)
            if(buf[0] == 0x57 && buf[1] == 0x45 && buf[2]==0x42 && buf[3] == 0x50 )
                    webp = true   ;             

            i = in.read(buf); // (16+)
            if(buf[0] == 0x41 && buf[1] == 0x4e && buf[2]==0x49 && buf[3] == 0x4d );
                vp8x = true;
                
            in.skip(14); // then next 4 should contain ANIM - 41 4e 49 4d
            i = in.read(buf);
            if(buf[0] == 0x41 && buf[1] == 0x4e && buf[2]==0x49 && buf[3] == 0x4d )
                anim = true;

        } catch (Exception e) {
            System.out.println("errrrrr "+e.getMessage());
        }
        return riff && webp && anim;

    }

您可以通过跳过 8 个字节直接读取 WEBP,然后计算并跳过 ANIM 之前的所有块,如果 ANIM 存在则读取该位置然后其动画 webp 图像否则为静态。

webp图片的文件布局 https://developers.google.com/speed/webp/docs/riff_container#example_file_layouts

参考:Google WEBP 规范https://developers.google.com/speed/webp/docs/riff_container


1
投票
def is_webp_animation(img_content):
    # https://developers.google.com/speed/webp/docs/riff_container#extended_file_format
    # webp Animation image.
    return len(img_content) > 20 and img_content[0:4] == b'RIFF' and img_content[8:12] == b'WEBP' \
            and img_content[12:16] == b'VP8X' \
            and int.from_bytes(img_content[20:21], 'little') & 2 == 2

0
投票

这是我在 BASH (Linux) 中的解决方案。在 Debian 12 中工作,无需添加任何所需的软件。搜索动画 webp 文件并将其复制到桌面。很容易修改我的脚本以满足您的需要。一些想法来自这里。

#!/bin/bash
file=$(zenity  --file-selection --filename=$HOME/ --title="Choose a directory to convert all file" --directory) ## Directory select.
result=0
rm "/dev/shm/findaniwebp.txt" 2> /dev/null
rm "/dev/shm/findfiles.txt" 2> /dev/null
find "$file" -name lost+found -prune -o -name '*.webp' >> "/dev/shm/findfiles.txt"

{
input="/dev/shm/findfiles.txt"
while IFS= read -r "line"
do
result=$(echo $(grep -c "ANMF" "$line"))
if [ "$result" -ge 10 ]; then
echo "Animated webp is found !"
echo $line
echo $line >> "/dev/shm/findaniwebp.txt"
fi
done < "$input"
}

if [ ! -f "/dev/shm/findaniwebp.txt" ]
then
aniwebp=0
else
aniwebp=$(wc -l < "/dev/shm/findaniwebp.txt")
echo "Finding finish (webp only) , with file to move : $aniwebp"
fi

if [ "$aniwebp" -ge "1" ]; then
if zenity --no-wrap --question --text="Do you want to COPY theseS fileS to $HOME/Desktop ?"
then
{
input="/dev/shm/findaniwebp.txt"
while IFS= read -r "line"
do
cp "$line" "$HOME"/Desktop
echo file moved...
done < "$input"
}
fi
else
echo "NO animated webp found!"
fi

rm "/dev/shm/findaniwebp.txt" 2> /dev/null
rm "/dev/shm/findfiles.txt" 2> /dev/null
read -n 1 -s -r -p "Press ENTER key to exit !"
exit
© www.soinside.com 2019 - 2024. All rights reserved.