From 2a7d45c98649bc9b2479e0ef2cf04fa404fa5358 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Sun, 25 Jan 2015 22:45:25 +0100 Subject: [PATCH] No need for ImageMagick to detected animated GIF --- classes/File.php | 7 +++- lib/imagefile.php | 39 ++++++++++++++++++++++- plugins/ImageMagick/ImageMagickPlugin.php | 4 +-- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/classes/File.php b/classes/File.php index 68da5c6f1b..65414977d3 100644 --- a/classes/File.php +++ b/classes/File.php @@ -384,6 +384,12 @@ class File extends Managed_DataObject */ public function getThumbnail($width=null, $height=null, $crop=false) { + // Get some more information about this file through our ImageFile class + $image = ImageFile::fromFileObject($this); + if ($image->animated && !common_config('image', 'resize_animated')) { + throw new UseFileAsThumbnailException($this->id); + } + if ($width === null) { $width = common_config('thumbnail', 'width'); $height = common_config('thumbnail', 'height'); @@ -398,7 +404,6 @@ class File extends Managed_DataObject // Get proper aspect ratio width and height before lookup // We have to do it through an ImageFile object because of orientation etc. // Only other solution would've been to rotate + rewrite uploaded files. - $image = ImageFile::fromFileObject($this); list($width, $height, $x, $y, $w, $h) = $image->scaleToFit($width, $height, $crop); diff --git a/lib/imagefile.php b/lib/imagefile.php index 967519a950..6aeab35816 100644 --- a/lib/imagefile.php +++ b/lib/imagefile.php @@ -52,7 +52,7 @@ class ImageFile var $height; var $width; var $rotate=0; // degrees to rotate for properly oriented image (extrapolated from EXIF etc.) - var $animated = false; // Animated image? (has more than 1 frame) + var $animated = null; // Animated image? (has more than 1 frame). null means untested function __construct($id=null, $filepath=null, $type=null, $width=null, $height=null) { @@ -98,6 +98,8 @@ class ImageFile } // If we ever write this back, Orientation should be set to '1' } + } elseif ($this->type === IMAGETYPE_GIF) { + $this->animated = $this->isAnimatedGif(); } Event::handle('FillImageFileMetadata', array($this)); @@ -500,6 +502,41 @@ class ImageFile is_null($cw) ? $width : intval($cw), is_null($ch) ? $height : intval($ch)); } + + /** + * Animated GIF test, courtesy of frank at huddler dot com et al: + * http://php.net/manual/en/function.imagecreatefromgif.php#104473 + * Modified so avoid landing inside of a header (and thus not matching our regexp). + */ + protected function isAnimatedGif() + { + if (!($fh = @fopen($this->filepath, '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) + // In total the header is maximum 10 bytes. + + // 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#s', $chunk, $matches); + // rewind in case we ended up in the middle of the header, but avoid + // infinite loop (i.e. don't rewind if we're already in the end). + if (!feof($fh) && ftell($fh) >= 9) { + fseek($fh, -9, SEEK_CUR); + } + } + + fclose($fh); + return $count > 1; + } } //PHP doesn't (as of 2/24/2010) have an imagecreatefrombmp so conditionally define one diff --git a/plugins/ImageMagick/ImageMagickPlugin.php b/plugins/ImageMagick/ImageMagickPlugin.php index ff2e666448..26335b6df8 100644 --- a/plugins/ImageMagick/ImageMagickPlugin.php +++ b/plugins/ImageMagick/ImageMagickPlugin.php @@ -65,12 +65,10 @@ class ImageMagickPlugin extends Plugin * @param array $info The response from getimagesize() */ public function onFillImageFileMetadata(ImageFile $imagefile) { - switch ($imagefile->type) { - case IMAGETYPE_GIF: + if (is_null($imagefile->animated) && $imagefile->type === IMAGETYPE_GIF) { $magick = new Imagick($imagefile->filepath); $magick = $magick->coalesceImages(); $imagefile->animated = $magick->getNumberImages()>1; - return true; } return true;