Closed ThomasLabstep closed 6 years ago
If you only need a resized version of just one frame, you can use a code like this:
$imagine = new Imagine\Imagick\Imagine();
$image = $imagine->open('path/to/your/huge.gif');
$firstFrame = $image->layers()->current();
$firstFrame->resize(new Imagine\Image\Box(60, 60));
$firstFrame->save('path/to/thumbnail.gif');
We switched back to gd. But then tiff are not supported. We will try with gmagick.
If it doesn't work, we will fork this library and remove the call to coalesceImages.
Thanks for the feedback.
Why don't you just call $image->layers()->current()
and work on it? It returns a Imagine\Image\ImageInterface
: you can call resize
on it...
You mean implement my own resize method at LiipImagineBundle level instead of using the default resize method?
That's a good idea!
namespace Liip\ImagineBundle\Imagine\Filter;
use Imagine\Exception\InvalidArgumentException;
use Imagine\Filter\FilterInterface;
use Imagine\Image\ImageInterface;
/**
* Filter for resizing an image relative to its existing dimensions.
*
* @author Jeremy Mikola <jmikola@gmail.com>
*/
class RelativeResize implements FilterInterface
{
private $method;
private $parameter;
/**
* Constructs a RelativeResize filter with the given method and argument.
*
* @param string $method BoxInterface method
* @param mixed $parameter Parameter for BoxInterface method
*
* @throws \Imagine\Exception\InvalidArgumentException
*/
public function __construct($method, $parameter)
{
if (!in_array($method, array('heighten', 'increase', 'scale', 'widen'))) {
throw new InvalidArgumentException(sprintf('Unsupported method: ', $method));
}
$this->method = $method;
$this->parameter = $parameter;
}
/**
* {@inheritdoc}
*/
public function apply(ImageInterface $image)
{
return $image->resize(call_user_func(array($image->getSize(), $this->method), $this->parameter));
}
}
I don't know LiipImagineBundle, but you can extend the existing RelativeResize
class and do something like this:
use Liip\ImagineBundle\Imagine\Filter\RelativeResize;
use Imagine\Image\ImageInterface;
class MyRelativeResize extends RelativeResize
{
/**
* {@inheritdoc}
*
* @see \Liip\ImagineBundle\Imagine\Filter\RelativeResize::apply()
*/
public function apply(ImageInterface $image)
{
return parent::apply($image()->layers()->current());
}
}
Thank you for your suggestion, I will try it later.
I'm looking into the config animated parameter. Because I don't want to animate the GIF.
For some reason, it's defined by default to false in LiipImagineBundle, and I'm trying to debug what imagine does with this variable.
/**
* @param array $options
* @param string $path
*/
private function prepareOutput(array $options, $path = null)
{
if (isset($options['format'])) {
$this->imagick->setImageFormat($options['format']);
}
var_dump($options['animated']);
exit;
if (isset($options['animated']) && true === $options['animated']) {
$format = isset($options['format']) ? $options['format'] : 'gif';
$delay = isset($options['animated.delay']) ? $options['animated.delay'] : null;
$loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0;
$options['flatten'] = false;
$this->layers->animate($format, $delay, $loops);
} else {
$this->layers->merge();
}
$this->applyImageOptions($this->imagick, $options, $path);
// flatten only if image has multiple layers
if ((!isset($options['flatten']) || $options['flatten'] === true) && count($this->layers) > 1) {
$this->flatten();
}
}
If animated
is not set (or is not true
), we call the merge
method, which basically assign the layers (frames in case of animated GIFs) to the image. This is useful in case you add new layers (frames) to the image, otherwise it basically does nothing.
Thanks for the clarification!
I'll now try your solution with 'apply($image()->layers()->current());'
You're so helpful 👍
A huge thank you. It works flawlessly. ❤️ ❤️ ❤️
class ThumbnailFilterLoader extends BaseThumbnailFilterLoader
{
/**
* @param ImageInterface $image
* @param array $options
*
* @return ImageInterface
*/
public function load(ImageInterface $image, array $options = [])
{
return parent::load($image->layers()->current(), $options);
}
}
Issue description
We are trying to resize a 2.7mb animated gif and it kills our server. On my mac, it reaches the timeout of 1min and uses 6gb of memory and 100% of cpu.
What's the PHP version you are using?
What's the imaging library you are using [gd/imagick/gmagick/any]?
What's the imaging library configuration
Minimal PHP code to reproduce the error:
The code that I want to be able to disable is:
How can we skip the "$this->layers->count() > 1" condition ? For now we will fork this library to leave only the else part. The dangerous code is "imagick->coalesceImages". We don't want animated resized gif, only a thumbnail is fine for us.
We are using LiipImagine. They have a 'animated' option that is false by default. But we still go down to this method.
Just wanted to report this issue.
Please advise.