1
0
mirror of https://github.com/Intervention/image.git synced 2025-01-17 20:28:21 +01:00

Add percent values as input for ImageInterface::removeAnimation()

This commit is contained in:
Oliver Vogel 2023-11-04 17:33:24 +01:00
parent 8f73dd81b7
commit a299100ff0
8 changed files with 70 additions and 34 deletions

View File

@ -374,7 +374,7 @@ abstract class AbstractImage implements ImageInterface
);
}
public function removeAnimation(int $position = 0): ImageInterface
public function removeAnimation(int|string $position = 0): ImageInterface
{
return $this->modify(
$this->resolveDriverClass('Modifiers\RemoveAnimationModifier', $position)

View File

@ -0,0 +1,29 @@
<?php
namespace Intervention\Image\Drivers\Abstract\Modifiers;
use Intervention\Image\Exceptions\InputException;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ModifierInterface;
abstract class AbstractRemoveAnimationModifier implements ModifierInterface
{
protected function chosenFrame($image, int|string $position): FrameInterface
{
if (is_int($position)) {
return $image->frame($position);
}
if (preg_match("/^(?P<percent>[0-9]{1,3})%$/", $position, $matches) != 1) {
throw new InputException(
'Input value of Image::removeAnimation() must be either integer or a percent value as string.'
);
}
$total = count($image);
$position = intval(round($total / 100 * intval($matches['percent'])));
$position = $position == $total ? $position - 1 : $position;
return $image->frame($position);
}
}

View File

@ -3,36 +3,25 @@
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Collection;
use Intervention\Image\Drivers\Gd\Image;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractRemoveAnimationModifier;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Traits\CanCheckType;
use Intervention\Image\Drivers\Gd\Image;
class RemoveAnimationModifier implements ModifierInterface
class RemoveAnimationModifier extends AbstractRemoveAnimationModifier
{
use CanCheckType;
public function __construct(protected int $position = 0)
public function __construct(protected int|string $position = 0)
{
//
}
public function apply(ImageInterface $image): ImageInterface
{
if (!$image->isAnimated()) {
throw new RuntimeException('Image is not animated.');
}
$image = $this->failIfNotClass($image, Image::class);
$frames = new Collection();
foreach ($image as $key => $frame) {
if ($this->position == $key) {
$frames->push($frame);
}
}
return $image->setFrames($frames);
return $image->setFrames(new Collection([
$this->chosenFrame($image, $this->position)
]));
}
}

View File

@ -3,36 +3,28 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Imagick;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Drivers\Abstract\Modifiers\AbstractRemoveAnimationModifier;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Drivers\Imagick\Image;
use Intervention\Image\Traits\CanCheckType;
class RemoveAnimationModifier implements ModifierInterface
class RemoveAnimationModifier extends AbstractRemoveAnimationModifier
{
use CanCheckType;
public function __construct(protected int $position = 0)
public function __construct(protected int|string $position = 0)
{
//
}
public function apply(ImageInterface $image): ImageInterface
{
if (!$image->isAnimated()) {
throw new RuntimeException('Image is not animated.');
}
$image = $this->failIfNotClass($image, Image::class);
// create new imagick with just one image
$imagick = new Imagick();
foreach ($image->getImagick() as $key => $core) {
if ($key == $this->position) {
$imagick->addImage($core->getImage());
}
}
$frame = $this->chosenFrame($image, $this->position);
$imagick->addImage($frame->core()->getImage());
return $image->setImagick($imagick);
}

View File

@ -0,0 +1,8 @@
<?php
namespace Intervention\Image\Exceptions;
class InputException extends \RuntimeException
{
//
}

View File

@ -79,10 +79,10 @@ interface ImageInterface extends Traversable, Countable
/**
* Remove all frames but keep the one at the specified position
*
* @param int $position
* @param int|string $position
* @return ImageInterface
*/
public function removeAnimation(int $position = 0): ImageInterface;
public function removeAnimation(int|string $position = 0): ImageInterface;
/**
* Apply given modifier to current image

View File

@ -22,4 +22,13 @@ class RemoveAnimationModifierTest extends TestCase
$this->assertEquals(1, count($image));
$this->assertEquals(1, count($result));
}
public function testApplyPercent(): void
{
$image = $this->createTestImage('animation.gif');
$this->assertEquals(8, count($image));
$result = $image->modify(new RemoveAnimationModifier('20%'));
$this->assertEquals(1, count($image));
$this->assertEquals(1, count($result));
}
}

View File

@ -22,4 +22,13 @@ class RemoveAnimationModifierTest extends TestCase
$this->assertEquals(1, count($image));
$this->assertEquals(1, count($result));
}
public function testApplyPercent(): void
{
$image = $this->createTestImage('animation.gif');
$this->assertEquals(8, count($image));
$result = $image->modify(new RemoveAnimationModifier('20%'));
$this->assertEquals(1, count($image));
$this->assertEquals(1, count($result));
}
}