diff --git a/src/Drivers/Abstract/AbstractImage.php b/src/Drivers/Abstract/AbstractImage.php index f615f238..f62cbef2 100644 --- a/src/Drivers/Abstract/AbstractImage.php +++ b/src/Drivers/Abstract/AbstractImage.php @@ -374,7 +374,7 @@ public function crop( ); } - public function removeAnimation(int $position = 0): ImageInterface + public function removeAnimation(int|string $position = 0): ImageInterface { return $this->modify( $this->resolveDriverClass('Modifiers\RemoveAnimationModifier', $position) diff --git a/src/Drivers/Abstract/Modifiers/AbstractRemoveAnimationModifier.php b/src/Drivers/Abstract/Modifiers/AbstractRemoveAnimationModifier.php new file mode 100644 index 00000000..e9a9099d --- /dev/null +++ b/src/Drivers/Abstract/Modifiers/AbstractRemoveAnimationModifier.php @@ -0,0 +1,29 @@ +frame($position); + } + + if (preg_match("/^(?P[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); + } +} diff --git a/src/Drivers/Gd/Modifiers/RemoveAnimationModifier.php b/src/Drivers/Gd/Modifiers/RemoveAnimationModifier.php index 744430be..a6451ea6 100644 --- a/src/Drivers/Gd/Modifiers/RemoveAnimationModifier.php +++ b/src/Drivers/Gd/Modifiers/RemoveAnimationModifier.php @@ -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) + ])); } } diff --git a/src/Drivers/Imagick/Modifiers/RemoveAnimationModifier.php b/src/Drivers/Imagick/Modifiers/RemoveAnimationModifier.php index f939ec2a..025d91b1 100644 --- a/src/Drivers/Imagick/Modifiers/RemoveAnimationModifier.php +++ b/src/Drivers/Imagick/Modifiers/RemoveAnimationModifier.php @@ -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); } diff --git a/src/Exceptions/InputException.php b/src/Exceptions/InputException.php new file mode 100644 index 00000000..5710e09f --- /dev/null +++ b/src/Exceptions/InputException.php @@ -0,0 +1,8 @@ +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)); + } } diff --git a/tests/Drivers/Imagick/Modifiers/RemoveAnimationModifierTest.php b/tests/Drivers/Imagick/Modifiers/RemoveAnimationModifierTest.php index 7a3eaf14..5ffba5d8 100644 --- a/tests/Drivers/Imagick/Modifiers/RemoveAnimationModifierTest.php +++ b/tests/Drivers/Imagick/Modifiers/RemoveAnimationModifierTest.php @@ -22,4 +22,13 @@ public function testApply(): void $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)); + } }