Can I detect animated gifs using php and gd?

I am currently facing some issues with resizing images using GD.

Everything works fine until I want to resize the animated gif, which provides the first frame on a black background.

I tried using getimagesize , but it only gives me sizes and nothing differentiates just any gif and animated.

Actual resizing is not required for animated gifs, just being able to skip them would be enough for our purposes.

Any clues?

PS. I do not have access to imagemagick.

Respectfully,

Kris

+38
php gd
Nov 11 '08 at 11:32
source share
6 answers

On the PHP manual page of the imagecreatefromgif() function, there is a short piece of code that should be what you need:

imagecreatefromgif comment # 59787 from ZeBadger

+17
Nov 11 '08 at 11:54
source share

When searching for a solution to the same problem, I noticed that on php.net there is a continuation of the code referenced by Davide and Kris, but, according to the author, there is less memory and, possibly, less disk intensively.

I will reproduce it here because it may be of interest.

source: 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; } 
+37
Jan 06 '09 at 9:39
source share

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; } 
+5
Nov 11 '08 at 12:18
source share

Reading the entire file with file_get_contents may take up too much memory if the specified file is too large. I reanalyzed a previously defined function that reads enough bytes to check for frames and returns as soon as it finds at least 2 frames.

 <?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; } 
+2
Feb 12 '17 at 18:27
source share

This is an improvement in the current voice response, but I don't have enough reputation for comment. The problem with this answer is that it reads the file in 100Kb blocks, and the end-of-frame marker can be split into 2 pieces. To fix this - add the last 20b of the previous frame to the following:

 <?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; } 
0
Dec 20 '17 at 13:27
source share

The animated GIF should have the following line

 "\x21\xFF\x0B\x4E\x45\x54\x53\x43\x41\x50\x45\x32\x2E\x30" 
-one
Aug 30 '13 at 4:19
source share



All Articles