1
0
mirror of https://github.com/Intervention/image.git synced 2025-08-07 14:26:31 +02: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( return $this->modify(
$this->resolveDriverClass('Modifiers\RemoveAnimationModifier', $position) $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; namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Collection; use Intervention\Image\Collection;
use Intervention\Image\Drivers\Gd\Image; use Intervention\Image\Drivers\Abstract\Modifiers\AbstractRemoveAnimationModifier;
use Intervention\Image\Exceptions\RuntimeException;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Traits\CanCheckType; use Intervention\Image\Traits\CanCheckType;
use Intervention\Image\Drivers\Gd\Image;
class RemoveAnimationModifier implements ModifierInterface class RemoveAnimationModifier extends AbstractRemoveAnimationModifier
{ {
use CanCheckType; use CanCheckType;
public function __construct(protected int $position = 0) public function __construct(protected int|string $position = 0)
{ {
// //
} }
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
if (!$image->isAnimated()) {
throw new RuntimeException('Image is not animated.');
}
$image = $this->failIfNotClass($image, Image::class); $image = $this->failIfNotClass($image, Image::class);
return $image->setFrames(new Collection([
$frames = new Collection(); $this->chosenFrame($image, $this->position)
foreach ($image as $key => $frame) { ]));
if ($this->position == $key) {
$frames->push($frame);
}
}
return $image->setFrames($frames);
} }
} }

View File

@@ -3,36 +3,28 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers; namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Imagick; use Imagick;
use Intervention\Image\Exceptions\RuntimeException; use Intervention\Image\Drivers\Abstract\Modifiers\AbstractRemoveAnimationModifier;
use Intervention\Image\Interfaces\ImageInterface; use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Drivers\Imagick\Image; use Intervention\Image\Drivers\Imagick\Image;
use Intervention\Image\Traits\CanCheckType; use Intervention\Image\Traits\CanCheckType;
class RemoveAnimationModifier implements ModifierInterface class RemoveAnimationModifier extends AbstractRemoveAnimationModifier
{ {
use CanCheckType; use CanCheckType;
public function __construct(protected int $position = 0) public function __construct(protected int|string $position = 0)
{ {
// //
} }
public function apply(ImageInterface $image): ImageInterface public function apply(ImageInterface $image): ImageInterface
{ {
if (!$image->isAnimated()) {
throw new RuntimeException('Image is not animated.');
}
$image = $this->failIfNotClass($image, Image::class); $image = $this->failIfNotClass($image, Image::class);
// create new imagick with just one image // create new imagick with just one image
$imagick = new Imagick(); $imagick = new Imagick();
foreach ($image->getImagick() as $key => $core) { $frame = $this->chosenFrame($image, $this->position);
if ($key == $this->position) { $imagick->addImage($frame->core()->getImage());
$imagick->addImage($core->getImage());
}
}
return $image->setImagick($imagick); 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 * Remove all frames but keep the one at the specified position
* *
* @param int $position * @param int|string $position
* @return ImageInterface * @return ImageInterface
*/ */
public function removeAnimation(int $position = 0): ImageInterface; public function removeAnimation(int|string $position = 0): ImageInterface;
/** /**
* Apply given modifier to current image * 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($image));
$this->assertEquals(1, count($result)); $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($image));
$this->assertEquals(1, count($result)); $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));
}
} }