代码之家  ›  专栏  ›  技术社区  ›  Kris

我可以用php和gd检测动画gif吗?

  •  43
  • Kris  · 技术社区  · 16 年前

    我目前遇到一些问题,使用gd调整图像大小。

    一切正常,直到我想调整动画的gif,它提供了黑色背景的第一帧。

    我试过用 getimagesize 但这只给了我尺寸,没有什么区别,只是任何一个GIF和一个动画。

    动画赠品不需要实际调整大小,只需跳过它们就足够了。

    有什么线索吗?

    我没有访问ImageMagick的权限。

    亲切的问候,

    克里斯

    6 回复  |  直到 7 年前
        1
  •  18
  •   TRiG    7 年前

    imagecreatefromgif() 您需要的功能:

    imagecreatefromgif comment #59787 by ZeBadger

        2
  •  38
  •   rr-    9 年前

    在寻找同一问题的解决方案时,我注意到php.net网站对davide和kris所指的代码进行了跟踪,但据作者介绍,内存占用较少,可能磁盘占用较少。

    我将在这里复制它,因为它可能很有趣。

    来源: 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;
    }
    
        3
  •  7
  •   Kris    16 年前

    工作功能如下:

    /**
     * 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;
    }
    
        4
  •  2
  •   hdogan    8 年前

    读取整个文件 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;
    }
    
        5
  •  0
  •   Simon - ShortPixel    7 年前

    这是对目前最受欢迎的答案的改进,但我还没有足够的声誉发表评论。这个答案的问题在于,它以100kb的块读取文件,而帧尾标记可能被分成两个块。修复方法是将前一帧的最后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;
    }
    
        6
  •  -1
  •   jmrk    7 年前

    动画gif必须有以下字符串

    "\x21\xFF\x0B\x4E\x45\x54\x53\x43\x41\x50\x45\x32\x2E\x30"
    

    我在一些动画gif上做过测试,看起来字符串在文件的位置781(在文件获取目录和strpos中找到)