From d59614578f379e779faa84598a2f2068a2c0181a Mon Sep 17 00:00:00 2001 From: Oliver Vogel Date: Sun, 26 Nov 2023 16:40:02 +0100 Subject: [PATCH] Add animation creation --- src/Drivers/Gd/Core.php | 10 +++++ src/Drivers/Gd/Driver.php | 59 ++++++++++++++++++++++++++++ src/Drivers/Imagick/Core.php | 10 +++++ src/Drivers/Imagick/Driver.php | 63 ++++++++++++++++++++++++++++++ src/Image.php | 12 ++++++ src/ImageManager.php | 5 +++ src/Interfaces/CoreInterface.php | 2 + src/Interfaces/DriverInterface.php | 8 ++++ src/Interfaces/ImageInterface.php | 8 ++++ 9 files changed, 177 insertions(+) diff --git a/src/Drivers/Gd/Core.php b/src/Drivers/Gd/Core.php index 97b1b9fa..71c024e9 100644 --- a/src/Drivers/Gd/Core.php +++ b/src/Drivers/Gd/Core.php @@ -45,4 +45,14 @@ class Core extends Collection implements CoreInterface return $this; } + + public function first(): FrameInterface + { + return parent::first(); + } + + public function last(): FrameInterface + { + return parent::last(); + } } diff --git a/src/Drivers/Gd/Driver.php b/src/Drivers/Gd/Driver.php index ae518b44..7c38b8f3 100644 --- a/src/Drivers/Gd/Driver.php +++ b/src/Drivers/Gd/Driver.php @@ -7,15 +7,26 @@ use Intervention\Image\Image; use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorProcessorInterface; use Intervention\Image\Interfaces\ColorspaceInterface; +use Intervention\Image\Interfaces\DriverInterface; use Intervention\Image\Interfaces\ImageInterface; class Driver extends AbstractDriver { + /** + * {@inheritdoc} + * + * @see DriverInterface::id() + */ public function id(): string { return 'GD'; } + /** + * {@inheritdoc} + * + * @see DriverInterface::createImage() + */ public function createImage(int $width, int $height): ImageInterface { // build new transparent GDImage @@ -34,11 +45,59 @@ class Driver extends AbstractDriver ); } + /** + * {@inheritdoc} + * + * @see DriverInterface::createAnimation() + */ + public function createAnimation(callable $init): ImageInterface + { + $animation = new class ($this) + { + public function __construct( + protected DriverInterface $driver, + public Core $core = new Core() + ) { + } + + public function add($source, float $delay = 1): self + { + $this->core->add( + $this->driver->handleInput($source)->core()->first()->setDelay($delay) + ); + + return $this; + } + + public function __invoke(): ImageInterface + { + return new Image( + $this->driver, + $this->core + ); + } + }; + + $init($animation); + + return call_user_func($animation); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::handleInput() + */ public function handleInput(mixed $input): ImageInterface|ColorInterface { return (new InputHandler())->handle($input); } + /** + * {@inheritdoc} + * + * @see DriverInterface::colorProcessor() + */ public function colorProcessor(ColorspaceInterface $colorspace): ColorProcessorInterface { return new ColorProcessor($colorspace); diff --git a/src/Drivers/Imagick/Core.php b/src/Drivers/Imagick/Core.php index cf068e9d..6fde6d7b 100644 --- a/src/Drivers/Imagick/Core.php +++ b/src/Drivers/Imagick/Core.php @@ -110,4 +110,14 @@ class Core implements CoreInterface, Iterator return $this; } + + public function first(): FrameInterface + { + return $this->frame(0); + } + + public function last(): FrameInterface + { + return $this->frame($this->count()); + } } diff --git a/src/Drivers/Imagick/Driver.php b/src/Drivers/Imagick/Driver.php index 9c1ea5d0..823007ab 100644 --- a/src/Drivers/Imagick/Driver.php +++ b/src/Drivers/Imagick/Driver.php @@ -9,15 +9,26 @@ use Intervention\Image\Image; use Intervention\Image\Interfaces\ColorInterface; use Intervention\Image\Interfaces\ColorProcessorInterface; use Intervention\Image\Interfaces\ColorspaceInterface; +use Intervention\Image\Interfaces\DriverInterface; use Intervention\Image\Interfaces\ImageInterface; class Driver extends AbstractDriver { + /** + * {@inheritdoc} + * + * @see DriverInterface::id() + */ public function id(): string { return 'Imagick'; } + /** + * {@inheritdoc} + * + * @see DriverInterface::createImage() + */ public function createImage(int $width, int $height): ImageInterface { $background = new ImagickPixel('rgba(0, 0, 0, 0)'); @@ -32,11 +43,63 @@ class Driver extends AbstractDriver return new Image($this, new Core($imagick)); } + /** + * {@inheritdoc} + * + * @see DriverInterface::createAnimation() + */ + public function createAnimation(callable $init): ImageInterface + { + $imagick = new Imagick(); + $imagick->setFormat('gif'); + + $animation = new class ($this, $imagick) + { + public function __construct( + protected DriverInterface $driver, + public Imagick $imagick + ) { + } + + public function add($source, float $delay = 1): self + { + $native = $this->driver->handleInput($source)->core()->native(); + $native->setImageDelay($delay * 100); + + $this->imagick->addImage($native); + + return $this; + } + + public function __invoke(): ImageInterface + { + return new Image( + $this->driver, + new Core($this->imagick) + ); + } + }; + + $init($animation); + + return call_user_func($animation); + } + + /** + * {@inheritdoc} + * + * @see DriverInterface::handleInput() + */ public function handleInput(mixed $input): ImageInterface|ColorInterface { return (new InputHandler())->handle($input); } + /** + * {@inheritdoc} + * + * @see DriverInterface::colorProcessor() + */ public function colorProcessor(ColorspaceInterface $colorspace): ColorProcessorInterface { return new ColorProcessor($colorspace); diff --git a/src/Image.php b/src/Image.php index 08e72e48..e1566732 100644 --- a/src/Image.php +++ b/src/Image.php @@ -142,6 +142,18 @@ final class Image implements ImageInterface, Countable return $this->core->loops(); } + /** + * {@inheritdoc} + * + * @see ImageInterface::setLoops() + */ + public function setLoops(int $loops): ImageInterface + { + $this->core->setLoops($loops); + + return $this; + } + /** * {@inheritdoc} * diff --git a/src/ImageManager.php b/src/ImageManager.php index ae3ec17a..b48e0185 100644 --- a/src/ImageManager.php +++ b/src/ImageManager.php @@ -41,6 +41,11 @@ final class ImageManager return $this->driver->handleInput($input); } + public function animate(callable $init): ImageInterface + { + return $this->driver->createAnimation($init); + } + private static function resolveDriver(string|DriverInterface $driver): DriverInterface { if (is_object($driver)) { diff --git a/src/Interfaces/CoreInterface.php b/src/Interfaces/CoreInterface.php index 16f78382..14320cc2 100644 --- a/src/Interfaces/CoreInterface.php +++ b/src/Interfaces/CoreInterface.php @@ -59,4 +59,6 @@ interface CoreInterface extends Traversable * @return CoreInterface */ public function setLoops(int $loops): CoreInterface; + + public function first(): FrameInterface; } diff --git a/src/Interfaces/DriverInterface.php b/src/Interfaces/DriverInterface.php index aa08890c..3443f2ef 100644 --- a/src/Interfaces/DriverInterface.php +++ b/src/Interfaces/DriverInterface.php @@ -28,6 +28,14 @@ interface DriverInterface */ public function createImage(int $width, int $height): ImageInterface; + /** + * Create new animated image + * + * @param callable $init + * @return ImageInterface + */ + public function createAnimation(callable $init): ImageInterface; + /** * Handle given input by decoding it to ImageInterface or ColorInterface * diff --git a/src/Interfaces/ImageInterface.php b/src/Interfaces/ImageInterface.php index be72095c..9b41ee4c 100644 --- a/src/Interfaces/ImageInterface.php +++ b/src/Interfaces/ImageInterface.php @@ -94,6 +94,14 @@ interface ImageInterface extends IteratorAggregate, Countable */ public function loops(): int; + /** + * Set loop count of animated image + * + * @param int $loops + * @return ImageInterface + */ + public function setLoops(int $loops): ImageInterface; + /** * Return exif data of current image *