There are flags in Webp header, ANIMATION among others. Small function to check it:
WebP头中有标志,动画等。检查它的小函数:
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.
Anim和ANMF来自下一个块标头。
RIFF container specification
RIFF容器规范
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
:
经过大量调查,我发现当在文本编辑器中打开WebP动画图像时,总是包含一些字符串,而非动画图像则不包含。这些字符串是ANMF和ANIM。我在我拥有的所有WebP图像中检查了这些字符串。所以这对我来说是完美的。以下是一些用PHP、Java脚本和壳牌脚本编写的解决方案:
In PHP:
在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:
在Java脚本中:
function isWebpAnimated(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
.
但在大型图像的情况下,PHP和Java无法很好地工作,所以最好的解决方案是使用Shell脚本,如果你有Ubuntu的话。
In Shell Script:
在外壳脚本中:
echo $(grep -c "ANMF" ~/animated.webp)
return 0 if non animated, else non zero value for animated.
如果未设置动画,则返回0,否则返回非零值。
EDIT: In Python
编辑:在Python中
def isWebpAnimated(src):
try:
with open(src, 'rb') as f:
data = f.read()
# Check if the file starts with 'RIFF' and contains 'WEBPVP8' or 'WEBPVP8X'
if data.startswith(b'RIFF') and (b'WEBPVP8' in data or b'WEBPVP8X' in data):
# The 'ANIM' indicating that the given file is Animated
return 1
else:
return 0
except Exception as err:
exit(f"Error Occure: {err}")
According Sven Liivak's isWebpAnimated()
... there is a small bug.
根据Sven Liivak的isWebpAnimated().有一个小bug。
fseek($fh, 16);
FSeek($fh,16);
should be:
应该是:
fseek($fh, 20);
FSeek($fh,20);
Because postion 16
is the chunk_size
position in VP8X
.
But we need the flag
position which is at 20
.
因为位置16是VP8X中的CHUNK_SIZE位置。但我们需要旗帜的位置在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;
}
This is my java code, it works for me.
这是我的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;
}
Fixing @ccomangee's solution.
Some static webp images would be detected as animated and can cause issue in the application.
修复@ccomangee的解决方案。某些静态WebP图像会被检测为动画,可能会导致应用程序出现问题。
I had extracted webp frames and saved as webp images and tried to identify by checking VP8X signature and it exists in given position although It is static image. So if there is VP8X it does not mean that the image would be animated having more than one frames.
我提取了webp帧并保存为webp图像,并试图通过检查VP8X签名来识别,它存在于给定的位置,尽管它是静态图像。因此,如果有VP8X,这并不意味着图像将被动画具有多个帧。
I tried few images with my solution and the result is below:
我用我的解决方案尝试了几个图像,结果如下:
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? ]
Here all images are named according to its type.
anim-trans: animated image contains transparency (alpha channel support)
anim-solid: animated image having no transparency
static-trans and static-solid are static images.
这里所有的图像都是根据其类型命名的。动画-变换:动画图像包含透明度(Alpha通道支持)动画-实体:没有透明度的动画图像静态-变换和静态-实体是静态图像。
VP8L is loseless webp and VP8X contains extended features.
VP8 is surely static image.
VP8L是无损耗的WebP,而VP8X包含扩展功能。VP8肯定是静态图像。
If VP8X exists it could be static or animated most images would be animated.
如果VP8X存在,它可以是静态的,也可以是动画的,大多数图像都是动画的。
The solution is
解决方案是
Read 4 bytes -> 'RIFF'
Skip 4 bytes
Read 4 bytes -> 'WEBP'
Read 4 bytes -> 'VP8X' / 'VP8L' / 'VP8'
skip 14 bytes
Read 4 bytes -> 'ANIM'
读取4字节->‘RIFF’跳过4字节读取->‘WebP’读取4字节->‘VP8X’/‘VP8L’/‘VP8’跳过14字节读取4字节->‘动画’
Java Code:
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;
}
you can directly read WEBP by skipping 8 bytes then count and skipp all chunks before ANIM and read that position if ANIM exist then its animated webp image else static.
您可以通过跳过8个字节直接读取WebP,然后计算和跳过动画之前的所有块,并读取该位置,如果动画存在,则其动画WebP图像否则为静态。
File layout of webp images
https://developers.google.com/speed/webp/docs/riff_container#example_file_layouts
WebP图像https://developers.google.com/speed/webp/docs/riff_container#example_file_layouts的文件布局
Ref: Google WEBP specification https://developers.google.com/speed/webp/docs/riff_container
参考:Google WebP规范https://developers.google.com/speed/webp/docs/riff_container
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
This is my solution in BASH (Linux). Work in Debian 12 without any needed softwares added. Search and COPY animated webp files to desktop. It is easy to modify my script to accommodate your need. Some idea come from here.
这是我在Bash(Linux)中的解决方案。在Debian 12中工作,不需要添加任何需要的软件。搜索动画WebP文件并将其复制到桌面。它很容易修改我的脚本,以适应您的需要。一些想法是从这里产生的。
#!/bin/bash
file=$(zenity --file-selection --filename=$HOME/ --title="Choose a directory to convert all file" --directory)
rm "/dev/shm/findaniwebp.txt" 2> /dev/null
rm "/dev/shm/findfiles.txt" 2> /dev/null
find "$file" -iname '*.webp' >> "/dev/shm/findfiles.txt" 2>/dev/null
{
result=0
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
I apologize for joining this discussion late, but I'm also seeking a Python-based solution for offline use.
很抱歉这么晚才参加这个讨论,但我也在寻找一种脱机使用的基于Python的解决方案。
Although I'm not well-versed in PHP or JavaScript, I do have some knowledge of Python. Here's what I've discovered: you can determine whether a WebP image is an animation or a static image using the Python Imaging Library (PIL).
虽然我不太精通PHP或JavaScript,但我对Python有一定的了解。下面是我的发现:您可以使用Python成像库(PIL)来确定WebP图像是动画图像还是静态图像。
To count the number of frames in a WebP image and identify animations, you can utilize PIL's Image
and ImageSequence
modules. Here's a Python script to accomplish this:
要计算WebP图像中的帧数量并识别动画,可以使用PIL的Image和ImageSequence模块。以下是实现这一点的一个Python脚本:
from PIL import Image, ImageSequence
def is_animation(file):
image = Image.open(file)
count = 0
for frame in ImageSequence.Iterator(image):
count += 1
return count > 1
By using this code, you can call the is_animation
function, passing the file path as an argument. If the image contains more than one frame, the function will return True
, indicating that it's an animation; otherwise, it will return False
for a static image.
通过使用此代码,您可以调用is_Animation函数,并将文件路径作为参数传递。如果图像包含多个帧,该函数将返回True,指示它是动画;否则,它将为静态图像返回False。
更多回答
?true:false
can be removed, it's not necessary to change a boolean to a boolean.
?TRUE:FALSE可以删除,不需要将布尔值更改为布尔值。
Note that this solution will produce false-positives in rare cases when some bytes in the file happen to contain the same binary values as the string "ANMF". Parsing the webp header as suggested in the other answers would be more reliable.
请注意,当文件中的某些字节恰好包含与字符串“ANMF”相同的二进制值时,此解决方案将在极少数情况下产生误报。按照其他答案中的建议解析WebP报头会更可靠。
Also it would work equally fast for files of any size, since you only need to read a few bytes at the very beginning of the file.
此外,对于任何大小的文件,它的运行速度都一样快,因为您只需要在文件的最开始读取几个字节。
In PHP, the if
, else
and return
blocks can be replaced by return ($where !== FALSE);
.
在PHP中,IF、ELSE和RETURN块可以替换为RETURN($WHERE!==FALSE);。
this is the correct answer. the other one always returns true for any webp
这是正确的答案。对于任何WebP,另一个总是返回TRUE
some webp contains VP8L
一些WebP包含VP8L
I had extracted frames from webp and those static frames are detected as animated according to this function. I think we should also check for ANIM header
我已经从WebP中提取了帧,根据这个函数,这些静态帧被检测为动画。我想我们也应该检查一下动漫标题
我是一名优秀的程序员,十分优秀!