我可以使用 php 和 gd 检测动画 gif 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/280658/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I detect animated gifs using php and gd?
提问by Kris
I'm currently running into some issues resizing images using GD.
我目前在使用 GD 调整图像大小时遇到了一些问题。
Everything works fine until i want to resize an animated gif, which delivers the first frame on a black background.
一切正常,直到我想调整动画 gif 的大小,它在黑色背景上提供第一帧。
I've tried using getimagesizebut that only gives me dimensions and nothing to distinguish between just any gif and an animated one.
我试过使用,getimagesize但这只给了我尺寸,没有什么可以区分任何 gif 和动画。
Actual resizing is not required for animated gifs, just being able to skip them would be enough for our purposes.
动画 gif 不需要实际调整大小,只需能够跳过它们就足以满足我们的目的。
Any clues?
有什么线索吗?
PS. I don't have access to imagemagick.
附注。我无权访问 imagemagick。
Kind regards,
亲切的问候,
Kris
克里斯
采纳答案by Davide Gualano
There is a brief snippet of code in the PHP manual page of the imagecreatefromgif()function that should be what you need:
该imagecreatefromgif()函数的 PHP 手册页中有一段简短的代码片段,应该是您所需要的:
回答by Martijn Heemels
While searching for a solution to the same problem I noticed that the php.net site has a follow-up to the code Davide and Kris are referring to, but, according to the author, less memory-intensive, and possibly less disk-intensive.
在寻找相同问题的解决方案时,我注意到 php.net 站点对 Davide 和 Kris 所指的代码进行了跟进,但是,据作者称,内存密集型和磁盘密集型可能更少.
I'll replicate it here, because it may be of interest.
我会在这里复制它,因为它可能会引起人们的兴趣。
source: http://www.php.net/manual/en/function.imagecreatefromgif.php#88005
来源:http: //www.php.net/manual/en/function.imagecreatefromgif.php#88005
function is_ani($filename) {
if(!($fh = @fopen($filename, 'rb')))
return false;
$count = 0;
//an animated gif contains multiple "frames", with each frame having a
//header made up of:
// * a static 4-byte sequence (\x00\x21\xF9\x04)
// * 4 variable bytes
// * a static 2-byte sequence (\x00\x2C)
// We read through the file til we reach the end of the file, or we've found
// at least 2 frame headers
while(!feof($fh) && $count < 2) {
$chunk = fread($fh, 1024 * 100); //read 100kb at a time
$count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00[\x2C\x21]#s', $chunk, $matches);
}
fclose($fh);
return $count > 1;
}
回答by Kris
Here's the working function:
这是工作功能:
/**
* Thanks to ZeBadger for original example, and Davide Gualano for pointing me to it
* Original at http://it.php.net/manual/en/function.imagecreatefromgif.php#59787
**/
function is_animated_gif( $filename )
{
$raw = file_get_contents( $filename );
$offset = 0;
$frames = 0;
while ($frames < 2)
{
$where1 = strpos($raw, "\x00\x21\xF9\x04", $offset);
if ( $where1 === false )
{
break;
}
else
{
$offset = $where1 + 1;
$where2 = strpos( $raw, "\x00\x2C", $offset );
if ( $where2 === false )
{
break;
}
else
{
if ( $where1 + 8 == $where2 )
{
$frames ++;
}
$offset = $where2 + 1;
}
}
}
return $frames > 1;
}
回答by hdogan
Reading whole file with file_get_contentsmay take too much memory if the given file is too large. I've re-factored the function previously given which reads just enough bytes to check frames and returns as soon as it finds at least 2 frames.
file_get_contents如果给定的文件太大,读取整个文件可能会占用太多内存。我已经重构了之前给出的函数,它读取刚好足够的字节来检查帧并在找到至少 2 个帧后立即返回。
<?php
/**
* Detects animated GIF from given file pointer resource or filename.
*
* @param resource|string $file File pointer resource or filename
* @return bool
*/
function is_animated_gif($file)
{
$fp = null;
if (is_string($file)) {
$fp = fopen($file, "rb");
} else {
$fp = $file;
/* Make sure that we are at the beginning of the file */
fseek($fp, 0);
}
if (fread($fp, 3) !== "GIF") {
fclose($fp);
return false;
}
$frames = 0;
while (!feof($fp) && $frames < 2) {
if (fread($fp, 1) === "\x00") {
/* Some of the animated GIFs do not contain graphic control extension (starts with 21 f9) */
if (fread($fp, 1) === "\x2c" || fread($fp, 2) === "\x21\xf9") {
$frames++;
}
}
}
fclose($fp);
return $frames > 1;
}
回答by Simon - ShortPixel
This is an improvement of the current top voted answer but I don't have enough reputation to comment yet. The problem with that answer is that it reads the file in 100Kb chunks and the end of frame marker might be split in between 2 chunks. A fix for that is to add the last 20b of the previous frame to the next one:
这是对当前最高投票答案的改进,但我还没有足够的声誉发表评论。该答案的问题在于它以 100Kb 的块读取文件,并且帧尾标记可能会分成 2 个块。解决方法是将前一帧的最后 20b 添加到下一帧:
<?php
function is_ani($filename) {
if(!($fh = @fopen($filename, 'rb')))
return false;
$count = 0;
//an animated gif contains multiple "frames", with each frame having a
//header made up of:
// * a static 4-byte sequence (\x00\x21\xF9\x04)
// * 4 variable bytes
// * a static 2-byte sequence (\x00\x2C) (some variants may use \x00\x21 ?)
// We read through the file til we reach the end of the file, or we've found
// at least 2 frame headers
$chunk = false;
while(!feof($fh) && $count < 2) {
//add the last 20 characters from the previous string, to make sure the searched pattern is not split.
$chunk = ($chunk ? substr($chunk, -20) : "") . fread($fh, 1024 * 100); //read 100kb at a time
$count += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches);
}
fclose($fh);
return $count > 1;
}
回答by user2731504
Animated GIF must have the following string
动画 GIF 必须具有以下字符串
"\x21\xFF\x0B\x4E\x45\x54\x53\x43\x41\x50\x45\x32\x2E\x30"
I've tested on a few animated gifs and it seem the string is at the pos 781 of a file (found with file_get_contents and strpos)
我已经对一些动画 gif 进行了测试,似乎字符串位于文件的 pos 781(通过 file_get_contents 和 strpos 找到)

