I am resizing an animated gif and adding a background to it using the imagick extension in PHP.
This is the code I am using:
$image = new Imagick('myfile.gif');
$image = $image->coalesceimages();
$final = new \Imagick();
foreach ($image as $frame){
$frame->thumbnailImage($width, $height, true);
$geometry = $image->getImageGeometry();
$x = ( $width - $geometry['width'] ) / 2;
$y = ( $height - $geometry['height'] ) / 2;
$canvas = new \Imagick();
$canvas->newImage( $width, $height, $background);
$canvas->compositeImage( $image, \Imagick::COMPOSITE_OVER, $x, $y );
$final->addimage($canvas);
}
$final->desconstructimages();
$final->writeImages('resized.gif', true);
The code works and the resized images are perfect. However, when resizing animated gifs, it takes quite a while.
With the above code, it takes about 10 seconds to resize a 36kb gif with 60 frames. With non-animated images, it takes about half a second.
I am running ImageMagick 6.8.1-0 2012-12-20
on Ubuntu 12.10 32-bit
.
Is there anyway to speed up the resizing?
Update:
I found out that thumbnailImage does not need to be called on every frame, so this is now what I am using:
$image = new Imagick('myfile.gif');
$image = $image->coalesceimages();
$final = new \Imagick();
$image->thumbnailImage($width, $height, true);
$geometry = $image->getImageGeometry();
$x = ( $width - $geometry['width'] ) / 2;
$y = ( $height - $geometry['height'] ) / 2;
foreach ($image as $frame){
$canvas = new \Imagick();
$canvas->newImage( $width, $height, $background);
$canvas->compositeImage( $image, \Imagick::COMPOSITE_OVER, $x, $y );
$final->addimage($canvas);
}
$final->desconstructimages();
$final->writeImages('resized.gif', true);
By only doing the thumbnailing once, I am now saving on average, 1 second (10%!) compared to before! So, to the guy who said, I should be happy with the performance and not complain, this is proof that you should investigate and improve things that you were previously happy with, otherwise you will always be a mediocre developer.
I am of course, trying to decrease the conversion time further, and will be doing some profiling to determine which calls are the most expensive and then target those.
After spending a while trying to optimize things, I ended up with an average time of around 6.5 seconds, which is much better than the initial 10 seconds.
I am now resizing the animation outside the loop and using optimizeImageLayers
which is faster than deconstructImages
and also keeps the filesize down.
$image = new Imagick('myfile.gif');
$image = $image->coalesceimages();
$final = new \Imagick();
foreach ($image as $frame){
$image->thumbnailImage($width, $height, true);
$geometry = $image->getImageGeometry();
$x = ( $width - $geometry['width'] ) / 2;
$y = ( $height - $geometry['height'] ) / 2;
$canvas = new \Imagick();
$canvas->newImage( $width, $height, $background);
$canvas->compositeImage( $image, \Imagick::COMPOSITE_OVER, $x, $y );
$final->addimage($canvas);
}
$final = $final->optimizedImageLayers();
$final->writeImages('resized.gif', true);
This is currently what I am using and am quite happy with it. However, I am will be looking at tweaking imagemagick's settings and playing with the color depth, etc to make it better, once I find some spare time of course :)