From 6eb9f92fba090a12e4e835f447e4b03775c0fd9c Mon Sep 17 00:00:00 2001 From: passchn <77938819+passchn@users.noreply.github.com> Date: Sun, 25 Jan 2026 12:31:47 +0100 Subject: [PATCH 1/9] [iv3] install intervention v3 and move all usages to facades --- composer.json | 2 +- src/ImageCreation/FilterInterface.php | 10 +++ src/ImageCreation/ImageInterface.php | 16 ++++ src/ImageCreation/ImageManagerInterface.php | 10 +++ src/ImageCreation/ImageManagerLocator.php | 46 ++++++++++ .../Intervention/InterventionImageFacade.php | 44 ++++++++++ .../InterventionImageManagerFacade.php | 24 +++++ src/Utilities/ImageAsset.php | 88 ++++++++++--------- 8 files changed, 199 insertions(+), 41 deletions(-) create mode 100644 src/ImageCreation/FilterInterface.php create mode 100644 src/ImageCreation/ImageInterface.php create mode 100644 src/ImageCreation/ImageManagerInterface.php create mode 100644 src/ImageCreation/ImageManagerLocator.php create mode 100644 src/ImageCreation/Intervention/InterventionImageFacade.php create mode 100644 src/ImageCreation/Intervention/InterventionImageManagerFacade.php diff --git a/composer.json b/composer.json index 57b6256..b11ef87 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "php": ">=8.2", "ext-fileinfo": "*", "cakephp/cakephp": "^5.1", - "intervention/image": "^2.7.2", + "intervention/image": "^3.11", "josegonzalez/cakephp-upload": "^8", "league/csv": "^9.8", "nette/utils": "^3.2 || ^4.0.0" diff --git a/src/ImageCreation/FilterInterface.php b/src/ImageCreation/FilterInterface.php new file mode 100644 index 0000000..9f1a949 --- /dev/null +++ b/src/ImageCreation/FilterInterface.php @@ -0,0 +1,10 @@ + ImageManager::imagick( + options: Configure::read('AssetsPlugin.ImageAsset.imagickOptions', []), + ), + 'gd', + GdDriver::class => ImageManager::gd( + options: Configure::read('AssetsPlugin.ImageAsset.gdOptions', []), + ), + default => throw new \LogicException('no driver configured'), + }, + ); + + return $manager; + } + + public static function setImageManager(ImageManagerInterface $manager): void + { + self::$manager = $manager; + } +} diff --git a/src/ImageCreation/Intervention/InterventionImageFacade.php b/src/ImageCreation/Intervention/InterventionImageFacade.php new file mode 100644 index 0000000..fada26b --- /dev/null +++ b/src/ImageCreation/Intervention/InterventionImageFacade.php @@ -0,0 +1,44 @@ +interventionImage->width(); + } + + public function height(): int + { + return $this->interventionImage->height(); + } + + /** + * @see MediaType + */ + public function mime(): string + { + return $this->interventionImage->origin()->mediaType(); + } + + public function save(string $absolutePath, ?int $quality, ?string $format): void + { + if ($format !== null) { + $absolutePath .= $absolutePath . '.' . $format; + } + + $this->interventionImage->save($absolutePath, quality: $quality); + } +} diff --git a/src/ImageCreation/Intervention/InterventionImageManagerFacade.php b/src/ImageCreation/Intervention/InterventionImageManagerFacade.php new file mode 100644 index 0000000..20a8584 --- /dev/null +++ b/src/ImageCreation/Intervention/InterventionImageManagerFacade.php @@ -0,0 +1,24 @@ +interventionImageManager->read($absolutePath), + ); + } +} diff --git a/src/Utilities/ImageAsset.php b/src/Utilities/ImageAsset.php index 3ca6780..ef642e5 100644 --- a/src/Utilities/ImageAsset.php +++ b/src/Utilities/ImageAsset.php @@ -6,14 +6,16 @@ use Assets\Error\FileNotFoundException; use Assets\Error\FilterNotFoundException; use Assets\Error\UnkownErrorException; +use Assets\ImageCreation\FilterInterface; +use Assets\ImageCreation\ImageInterface; +use Assets\ImageCreation\ImageManagerInterface; +use Assets\ImageCreation\ImageManagerLocator; use Assets\Model\Entity\Asset; use Cake\Core\Configure; use Cake\I18n\DateTime; use Cake\View\Helper\HtmlHelper; use Cake\View\View; use Exception; -use Intervention\Image\Image; -use Intervention\Image\ImageManager; use InvalidArgumentException; use Nette\Utils\FileSystem; use Nette\Utils\Json; @@ -29,7 +31,7 @@ * * To just get a public path from /webroot, call getPath() */ -class ImageAsset +final class ImageAsset { private Asset $asset; @@ -41,11 +43,11 @@ class ImageAsset private array $modifications; - private ?Image $image; + private ?ImageInterface $image = null; private ?string $format; - private ?string $filename; + private ?string $filename = null; private string $css; @@ -62,7 +64,6 @@ public function __construct(Asset $asset, int $quality = 90) $this->asset = $asset; $this->quality = $quality; $this->modifications = []; - $this->image = null; $this->format = $this->asset->filetype; $this->filename = null; $this->lazyLoading = true; @@ -82,8 +83,8 @@ public function __construct(Asset $asset, int $quality = 90) * @param array $options - optional: * - title (string): for alt-parameter in html-output * - quality (int): for jpg compression - * @throws \InvalidArgumentException when no file was found * @return self + * @throws InvalidArgumentException when no file was found */ public static function createFromPath(string $path, array $options = []): self { @@ -117,7 +118,7 @@ public static function createFromPath(string $path, array $options = []): self $quality = $options['quality'] ?? 90; - return new ImageAsset($asset, (int)$quality); + return new self($asset, (int)$quality); } /** @@ -127,7 +128,7 @@ public static function createFromPath(string $path, array $options = []): self * @param int $width Width in px * @return $this */ - public function scaleWidth(int $width) + public function scaleWidth(int $width): self { $this->trackModification('widen', [$width]); @@ -137,7 +138,7 @@ public function scaleWidth(int $width) /** * @return $this */ - public function toWebp() + public function toWebp(): self { $this->trackModification('encode', ['webp']); $this->format = 'webp'; @@ -148,7 +149,7 @@ public function toWebp() /** * @return $this */ - public function toJpg() + public function toJpg(): self { $this->trackModification('encode', ['jpg']); $this->format = 'jpg'; @@ -162,7 +163,7 @@ public function toJpg() * @param string $css HTML class which will be added on render * @return $this */ - public function setCSS(string $css) + public function setCSS(string $css): self { $this->css = $css; @@ -173,7 +174,7 @@ public function setCSS(string $css) * @param bool $lazyLoading Control if the image shall be loaded lazily when rendered as Html * @return $this */ - public function setLazyLoading(bool $lazyLoading = true) + public function setLazyLoading(bool $lazyLoading = true): self { $this->lazyLoading = $lazyLoading; @@ -189,7 +190,7 @@ public function setLazyLoading(bool $lazyLoading = true) * @param string|null $filename the custom filename * @return $this */ - public function setFilename(?string $filename) + public function setFilename(?string $filename): self { $this->filename = $filename; @@ -197,16 +198,22 @@ public function setFilename(?string $filename) } /** - * e.g. - * ImageAsset::applyFilter(EpaperFilter::class, ['kombi']) - * !! Don't pass an ImageManager instance, only string or int properties. - * * @param string $filter ClassName of the Filter - * @param array $properties Will be passed after the ImageManager instance when calling the Filter's constructor. + * @param array $properties Will be passed to the Filter's constructor * @return $this */ - public function applyFilter(string $filter, array $properties = []) + public function applyFilter(string $filter, array $properties = []): self { + if (!is_a($filter, FilterInterface::class, allow_string: true)) { + throw new InvalidArgumentException( + sprintf( + 'Argument $filter of type `%s` does not implement `%s`.', + get_debug_type($filter), + FilterInterface::class, + ), + ); + } + $this->trackModification('filter_' . $filter, $properties); return $this; @@ -221,7 +228,7 @@ public function applyFilter(string $filter, array $properties = []) * @return $this * @link https://image.intervention.io/v2 */ - public function modify(string $method, mixed ...$params) + public function modify(string $method, mixed ...$params): self { $this->trackModification($method, $params); @@ -262,7 +269,7 @@ public function getHTML(array $params = []): string if (!$this->image) { $manager = $this->getImageManager(); - $this->image = $manager->make($this->getAbsolutePath()); + $this->image = $manager->read($this->getAbsolutePath()); } $default_params = [ @@ -407,7 +414,7 @@ private function render() $manager = $this->getImageManager(); try { - $image = $manager->make($this->asset->absolute_path); + $image = $manager->read($this->asset->absolute_path); } catch (Exception $e) { throw new UnkownErrorException("Could not call ImageManager::make on Asset #{$this->asset->id}. Error: {$e->getMessage()}."); } @@ -423,12 +430,9 @@ private function render() } /** - * @param \Intervention\Image\Image $image The image instance - * @param \Intervention\Image\ImageManager $manager The manager instance - * @return \Intervention\Image\Image * @throws \Assets\Error\FilterNotFoundException */ - private function applyModifications(Image $image, ImageManager $manager): Image + private function applyModifications(ImageInterface $image, ImageManagerInterface $manager): ImageInterface { $modifications = $this->modifications; unset($modifications['noApi']); @@ -437,12 +441,23 @@ private function applyModifications(Image $image, ImageManager $manager): Image if (str_contains($method, 'filter_')) { $filterClassName = Strings::after($method, 'filter_') ?? ''; if (!class_exists($filterClassName)) { - throw new FilterNotFoundException("Filter {$filterClassName} does not exist. "); + throw new FilterNotFoundException( + sprintf( + 'Filter `%s` does not exist.', + $filterClassName, + ), + ); + } + if (!is_a($filterClassName, FilterInterface::class, allow_string: true)) { + throw new FilterNotFoundException( + sprintf( + 'Filter `%s` does not implement `%s`.', + $filterClassName, + FilterInterface::class, + ), + ); } - /** - * @var \Intervention\Image\Filters\FilterInterface $filter - */ $filter = new $filterClassName($manager, ...$params); $image = $filter->applyFilter($image); continue; @@ -455,15 +470,8 @@ private function applyModifications(Image $image, ImageManager $manager): Image return $image; } - /** - * @return \Intervention\Image\ImageManager - */ - private function getImageManager(): ImageManager + private function getImageManager(): ImageManagerInterface { - $driver = Configure::read('AssetsPlugin.ImageAsset.driver', 'gd'); - - return new ImageManager([ - 'driver' => $driver, - ]); + return ImageManagerLocator::getImageManager(); } } From c99fd781b1ca28398afba5c21e5b937621fe5e10 Mon Sep 17 00:00:00 2001 From: passchn <77938819+passchn@users.noreply.github.com> Date: Sun, 25 Jan 2026 13:05:25 +0100 Subject: [PATCH 2/9] [iv3] map legacy modifiers --- src/ImageCreation/ImageInterface.php | 5 +++ src/ImageCreation/ImageManagerLocator.php | 13 +++++--- .../Intervention/InterventionImageFacade.php | 32 +++++++++++++++++- .../InterventionImageManagerFacade.php | 5 +++ .../Intervention/LegacySupport.php | 33 +++++++++++++++++++ src/Utilities/ImageAsset.php | 2 +- 6 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 src/ImageCreation/Intervention/LegacySupport.php diff --git a/src/ImageCreation/ImageInterface.php b/src/ImageCreation/ImageInterface.php index e372401..70f7f64 100644 --- a/src/ImageCreation/ImageInterface.php +++ b/src/ImageCreation/ImageInterface.php @@ -13,4 +13,9 @@ public function height(): int; public function mime(): string; public function save(string $absolutePath, ?int $quality, ?string $format): void; + + /** + * Modify the image based on the underlying implementation. + */ + public function modify(string $modifier, array $params): self; } diff --git a/src/ImageCreation/ImageManagerLocator.php b/src/ImageCreation/ImageManagerLocator.php index bdd99db..ef12dae 100644 --- a/src/ImageCreation/ImageManagerLocator.php +++ b/src/ImageCreation/ImageManagerLocator.php @@ -5,6 +5,7 @@ namespace Assets\ImageCreation; use Assets\ImageCreation\Intervention\InterventionImageManagerFacade; +use Assets\ImageCreation\Intervention\LegacySupport; use Cake\Core\Configure; use Intervention\Image\Drivers\Imagick\Driver as ImagickDriver; use Intervention\Image\Drivers\Gd\Driver as GdDriver; @@ -21,22 +22,24 @@ public static function getImageManager(): ImageManagerInterface } $driver = Configure::read('AssetsPlugin.ImageAsset.driver', 'gd'); + $legacyModifiersMap = Configure::read('AssetsPlugin.ImageAsset.legacyModifiersMap'); - $manager = self::$manager = new InterventionImageManagerFacade( + return self::$manager = new InterventionImageManagerFacade( match ($driver) { 'imagick', ImagickDriver::class => ImageManager::imagick( - options: Configure::read('AssetsPlugin.ImageAsset.imagickOptions', []), + ...Configure::read('AssetsPlugin.ImageAsset.imagickOptions', []), ), 'gd', GdDriver::class => ImageManager::gd( - options: Configure::read('AssetsPlugin.ImageAsset.gdOptions', []), + ...Configure::read('AssetsPlugin.ImageAsset.gdOptions', []), ), default => throw new \LogicException('no driver configured'), }, + legacyModifiersMap: $legacyModifiersMap !== null + ? $legacyModifiersMap + : LegacySupport::V2_TO_V3_MODIFIERS_MAP, ); - - return $manager; } public static function setImageManager(ImageManagerInterface $manager): void diff --git a/src/ImageCreation/Intervention/InterventionImageFacade.php b/src/ImageCreation/Intervention/InterventionImageFacade.php index fada26b..165ae17 100644 --- a/src/ImageCreation/Intervention/InterventionImageFacade.php +++ b/src/ImageCreation/Intervention/InterventionImageFacade.php @@ -4,14 +4,19 @@ namespace Assets\ImageCreation\Intervention; +use Assets\Error\InvalidArgumentException; use Assets\ImageCreation\ImageInterface; use Intervention\Image\MediaType; use Intervention\Image\Interfaces as Intervention; final class InterventionImageFacade implements ImageInterface { + /** + * @param array $legacyMdifiersMap + */ public function __construct( - private Intervention\ImageInterface $interventionImage + private Intervention\ImageInterface $interventionImage, + private array $legacyMdifiersMap, ) { } @@ -41,4 +46,29 @@ public function save(string $absolutePath, ?int $quality, ?string $format): void $this->interventionImage->save($absolutePath, quality: $quality); } + + public function modify(string $modifier, array $params): ImageInterface + { + if (method_exists($this->interventionImage, $modifier)) { + $this->interventionImage->{$modifier}(...$params); + return $this; + } + + $mappedFromLegacy = $this->legacyMdifiersMap[$modifier] ?? null; + + if ( + $mappedFromLegacy !== null + && method_exists($this->interventionImage, $mappedFromLegacy) + ) { + $this->interventionImage->{$mappedFromLegacy}(...$params); + return $this; + } + + throw new InvalidArgumentException( + sprintf( + 'Modifier `%s` does not exist', + $modifier, + ), + ); + } } diff --git a/src/ImageCreation/Intervention/InterventionImageManagerFacade.php b/src/ImageCreation/Intervention/InterventionImageManagerFacade.php index 20a8584..66560f0 100644 --- a/src/ImageCreation/Intervention/InterventionImageManagerFacade.php +++ b/src/ImageCreation/Intervention/InterventionImageManagerFacade.php @@ -10,8 +10,12 @@ final class InterventionImageManagerFacade implements ImageManagerInterface { + /** + * @param array $legacyModifiersMap + */ public function __construct( private Intervention\ImageManagerInterface $interventionImageManager, + private array $legacyModifiersMap, ) { } @@ -19,6 +23,7 @@ public function read(string $absolutePath): ImageInterface { return new InterventionImageFacade( $this->interventionImageManager->read($absolutePath), + $this->legacyModifiersMap, ); } } diff --git a/src/ImageCreation/Intervention/LegacySupport.php b/src/ImageCreation/Intervention/LegacySupport.php new file mode 100644 index 0000000..44c2cbc --- /dev/null +++ b/src/ImageCreation/Intervention/LegacySupport.php @@ -0,0 +1,33 @@ + 'create', + 'circle' => 'drawCircle', + 'ellipse' => 'drawEllipse', + 'line' => 'drawLine', + 'pixel' => 'drawPixel', + 'filter' => 'modify', + 'insert' => 'place', + 'make' => 'read', + 'mime' => 'encodedImage', + 'polygon' => 'drawPolygon', + 'rectangle' => 'drawRectangle', + 'limitColors'=> 'reduceColors', + 'getCore' => 'core', + 'orientate' => 'orient', + 'widen' => 'scale', + 'heighten' => 'scale', + 'fit' => 'cover', + ]; +} diff --git a/src/Utilities/ImageAsset.php b/src/Utilities/ImageAsset.php index ef642e5..72d5bf5 100644 --- a/src/Utilities/ImageAsset.php +++ b/src/Utilities/ImageAsset.php @@ -464,7 +464,7 @@ private function applyModifications(ImageInterface $image, ImageManagerInterface } $params = is_array($params) ? $params : [$params]; - $image->{$method}(...$params); + $image->modify($method, $params); } return $image; From 9843f7aaa424778ebdfea6590c06f1aacd42c2cb Mon Sep 17 00:00:00 2001 From: passchn <77938819+passchn@users.noreply.github.com> Date: Sun, 25 Jan 2026 13:36:47 +0100 Subject: [PATCH 3/9] [iv3] add fallback callbacks --- src/Error/ModificationFailedException.php | 11 +++ src/ImageCreation/ImageInterface.php | 3 + .../Intervention/InterventionImageFacade.php | 45 +++++++-- .../InterventionImageManagerFacade.php | 2 +- .../Intervention/LegacySupport.php | 93 +++++++++++++++---- 5 files changed, 126 insertions(+), 28 deletions(-) create mode 100644 src/Error/ModificationFailedException.php diff --git a/src/Error/ModificationFailedException.php b/src/Error/ModificationFailedException.php new file mode 100644 index 0000000..a3ddc08 --- /dev/null +++ b/src/Error/ModificationFailedException.php @@ -0,0 +1,11 @@ + $legacyMdifiersMap + * @param array $legacyMdifiersMap */ public function __construct( private Intervention\ImageInterface $interventionImage, private array $legacyMdifiersMap, - ) { + ) + { } public function width(): int @@ -49,8 +51,36 @@ public function save(string $absolutePath, ?int $quality, ?string $format): void public function modify(string $modifier, array $params): ImageInterface { + if ($params === []) { + throw new ModificationFailedException('Empty params given'); + } + + $modify = function (string $modifier, array $params, ?string $legacyModifier = null) { + try { + $this->interventionImage->{$modifier}(...$params); + } catch (\Throwable $throwable) { + + if ($legacyModifier === null) { + $callback = $this->legacyMdifiersMap[$modifier] ?? null; + if ($callback !== null && is_callable($callback)) { + $callback($this->interventionImage, ...$params); + } + } + + throw new ModificationFailedException( + sprintf( + 'Modification `%s` failed with params: %s.%s', + $modifier, + var_export($params, true), + $legacyModifier !== null ? ' Legacy: ' . $legacyModifier : '', + ), + previous: $throwable, + ); + } + }; + if (method_exists($this->interventionImage, $modifier)) { - $this->interventionImage->{$modifier}(...$params); + $modify($modifier, $params); return $this; } @@ -60,15 +90,10 @@ public function modify(string $modifier, array $params): ImageInterface $mappedFromLegacy !== null && method_exists($this->interventionImage, $mappedFromLegacy) ) { - $this->interventionImage->{$mappedFromLegacy}(...$params); + $modify($mappedFromLegacy, $params, $modifier); return $this; } - throw new InvalidArgumentException( - sprintf( - 'Modifier `%s` does not exist', - $modifier, - ), - ); + throw new ModificationFailedException(sprintf('Modifier `%s` does not exist', $modifier)); } } diff --git a/src/ImageCreation/Intervention/InterventionImageManagerFacade.php b/src/ImageCreation/Intervention/InterventionImageManagerFacade.php index 66560f0..d406dcb 100644 --- a/src/ImageCreation/Intervention/InterventionImageManagerFacade.php +++ b/src/ImageCreation/Intervention/InterventionImageManagerFacade.php @@ -11,7 +11,7 @@ final class InterventionImageManagerFacade implements ImageManagerInterface { /** - * @param array $legacyModifiersMap + * @param array $legacyModifiersMap */ public function __construct( private Intervention\ImageManagerInterface $interventionImageManager, diff --git a/src/ImageCreation/Intervention/LegacySupport.php b/src/ImageCreation/Intervention/LegacySupport.php index 44c2cbc..c4ae802 100644 --- a/src/ImageCreation/Intervention/LegacySupport.php +++ b/src/ImageCreation/Intervention/LegacySupport.php @@ -4,6 +4,9 @@ namespace Assets\ImageCreation\Intervention; +use Assets\Error\ModificationFailedException; +use Intervention\Image\Image; + final class LegacySupport { /** @@ -12,22 +15,78 @@ final class LegacySupport * Note: Signature might have changed. */ public const V2_TO_V3_MODIFIERS_MAP = [ - 'canvas' => 'create', - 'circle' => 'drawCircle', - 'ellipse' => 'drawEllipse', - 'line' => 'drawLine', - 'pixel' => 'drawPixel', - 'filter' => 'modify', - 'insert' => 'place', - 'make' => 'read', - 'mime' => 'encodedImage', - 'polygon' => 'drawPolygon', - 'rectangle' => 'drawRectangle', - 'limitColors'=> 'reduceColors', - 'getCore' => 'core', - 'orientate' => 'orient', - 'widen' => 'scale', - 'heighten' => 'scale', - 'fit' => 'cover', + // Name changed + 'canvas' => 'create', + 'circle' => 'drawCircle', + 'ellipse' => 'drawEllipse', + 'line' => 'drawLine', + 'pixel' => 'drawPixel', + 'filter' => 'modify', + 'insert' => 'place', + 'make' => 'read', + 'mime' => 'encodedImage', + 'polygon' => 'drawPolygon', + 'rectangle' => 'drawRectangle', + 'limitColors' => 'reduceColors', + 'getCore' => 'core', + 'orientate' => 'orient', + 'widen' => 'scale', + 'heighten' => 'scale', + 'fit' => 'cover', + // Signature changed + 'crop' => [self::class, 'legacyCrop'], + 'encode' => [self::class, 'legacyEncode'], + 'exif' => [self::class, 'legacyExif'], + 'fill' => [self::class, 'legacyFill'], + 'flip' => [self::class, 'legacyFlip'], + 'text' => [self::class, 'legacyText'], + 'resizeCanvas' => [self::class, 'legacyResizeCanvas'], + 'trim' => [self::class, 'legacyTrim'], + 'resize' => [self::class, 'legacyResize'], ]; + + public static function legacyCrop(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for crop not implemented'); + } + + public static function legacyEncode(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for encode not implemented'); + } + + public static function legacyExif(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for exif not implemented'); + } + + public static function legacyFill(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for fill not implemented'); + } + + public static function legacyFlip(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for flip not implemented'); + } + + public static function legacyText(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for text not implemented'); + } + + public static function legacyResizeCanvas(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for resizeCanvas not implemented'); + } + + public static function legacyTrim(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for trim not implemented'); + } + + public static function legacyResize(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for resize not implemented'); + } } From 9ed19dfd0b9ab974440cdddfe896fa4cdc8c1c6d Mon Sep 17 00:00:00 2001 From: passchn <77938819+passchn@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:13:19 +0100 Subject: [PATCH 4/9] [iv3] fix unit tests + add encode fallback --- .../Intervention/InterventionImageFacade.php | 12 ++++++++++-- src/ImageCreation/Intervention/LegacySupport.php | 15 +++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/ImageCreation/Intervention/InterventionImageFacade.php b/src/ImageCreation/Intervention/InterventionImageFacade.php index e6443e3..190efc0 100644 --- a/src/ImageCreation/Intervention/InterventionImageFacade.php +++ b/src/ImageCreation/Intervention/InterventionImageFacade.php @@ -9,6 +9,7 @@ use Assets\ImageCreation\ImageInterface; use Intervention\Image\MediaType; use Intervention\Image\Interfaces as Intervention; +use Nette\Utils\FileSystem; final class InterventionImageFacade implements ImageInterface { @@ -42,8 +43,14 @@ public function mime(): string public function save(string $absolutePath, ?int $quality, ?string $format): void { - if ($format !== null) { - $absolutePath .= $absolutePath . '.' . $format; + if ($format !== null && !str_ends_with($absolutePath, '.' . $format)) { + $absolutePath .= '.' . $format; + } + + $dir = dirname($absolutePath); + + if (!is_dir($dir)) { + FileSystem::createDir($dir); } $this->interventionImage->save($absolutePath, quality: $quality); @@ -64,6 +71,7 @@ public function modify(string $modifier, array $params): ImageInterface $callback = $this->legacyMdifiersMap[$modifier] ?? null; if ($callback !== null && is_callable($callback)) { $callback($this->interventionImage, ...$params); + return $this->interventionImage; } } diff --git a/src/ImageCreation/Intervention/LegacySupport.php b/src/ImageCreation/Intervention/LegacySupport.php index c4ae802..6691dae 100644 --- a/src/ImageCreation/Intervention/LegacySupport.php +++ b/src/ImageCreation/Intervention/LegacySupport.php @@ -5,7 +5,10 @@ namespace Assets\ImageCreation\Intervention; use Assets\Error\ModificationFailedException; +use Intervention\Image\Encoders\FileExtensionEncoder; +use Intervention\Image\FileExtension; use Intervention\Image\Image; +use Intervention\Image\Interfaces\EncodedImageInterface; final class LegacySupport { @@ -50,9 +53,17 @@ public static function legacyCrop(Image $image, mixed ...$params): Image throw new ModificationFailedException('legacy fallback for crop not implemented'); } - public static function legacyEncode(Image $image, mixed ...$params): Image + public static function legacyEncode(Image $image, mixed ...$params): EncodedImageInterface { - throw new ModificationFailedException('legacy fallback for encode not implemented'); + $format = $params[0] ?? null; + + if (!is_string($format)) { + throw new ModificationFailedException('no format given'); + } + + $encoder = new FileExtensionEncoder(FileExtension::from($format)); + + return $image->encode($encoder); } public static function legacyExif(Image $image, mixed ...$params): Image From 3ea5fd374e78b54ac7d0d55a8b3af09c51d5b070 Mon Sep 17 00:00:00 2001 From: passchn <77938819+passchn@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:40:34 +0100 Subject: [PATCH 5/9] [iv3] add manager methods + filter static factory method --- src/ImageCreation/FilterInterface.php | 2 ++ src/ImageCreation/ImageManagerInterface.php | 9 +++++++++ .../Intervention/InterventionImageManagerFacade.php | 13 +++++++++++++ src/Utilities/ImageAsset.php | 3 +-- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/ImageCreation/FilterInterface.php b/src/ImageCreation/FilterInterface.php index 9f1a949..d52efff 100644 --- a/src/ImageCreation/FilterInterface.php +++ b/src/ImageCreation/FilterInterface.php @@ -6,5 +6,7 @@ interface FilterInterface { + public static function create(ImageManagerInterface $manager, mixed ...$params): FilterInterface; + public function applyFilter(ImageInterface $image): ImageInterface; } diff --git a/src/ImageCreation/ImageManagerInterface.php b/src/ImageCreation/ImageManagerInterface.php index 6cf05fb..598c570 100644 --- a/src/ImageCreation/ImageManagerInterface.php +++ b/src/ImageCreation/ImageManagerInterface.php @@ -4,7 +4,16 @@ namespace Assets\ImageCreation; +use Assets\ImageCreation\Intervention\InterventionImageFacade; + interface ImageManagerInterface { public function read(string $absolutePath): ImageInterface; + + public function create(int $width, int $height): ImageInterface; + + /** + * @deprecated use {@see self::create()} + */ + public function canvas(int $width, int $height): ImageInterface; } diff --git a/src/ImageCreation/Intervention/InterventionImageManagerFacade.php b/src/ImageCreation/Intervention/InterventionImageManagerFacade.php index d406dcb..9085e80 100644 --- a/src/ImageCreation/Intervention/InterventionImageManagerFacade.php +++ b/src/ImageCreation/Intervention/InterventionImageManagerFacade.php @@ -26,4 +26,17 @@ public function read(string $absolutePath): ImageInterface $this->legacyModifiersMap, ); } + + public function create(int $width, int $height): ImageInterface + { + return new InterventionImageFacade( + $this->interventionImageManager->create($width, $height), + $this->legacyModifiersMap, + ); + } + + public function canvas(int $width, int $height): ImageInterface + { + return $this->create($width, $height); + } } diff --git a/src/Utilities/ImageAsset.php b/src/Utilities/ImageAsset.php index 72d5bf5..302183c 100644 --- a/src/Utilities/ImageAsset.php +++ b/src/Utilities/ImageAsset.php @@ -458,8 +458,7 @@ private function applyModifications(ImageInterface $image, ImageManagerInterface ); } - $filter = new $filterClassName($manager, ...$params); - $image = $filter->applyFilter($image); + $image = $filterClassName::create($manager, ...$params)->applyFilter($image); continue; } From fd498912268326cc61dedee3b8d8fa9ba677c461 Mon Sep 17 00:00:00 2001 From: passchn <77938819+passchn@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:06:53 +0100 Subject: [PATCH 6/9] [iv3] add getters for original intervention image --- src/ImageCreation/ImageInterface.php | 9 +++++++++ .../Intervention/InterventionImageFacade.php | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/ImageCreation/ImageInterface.php b/src/ImageCreation/ImageInterface.php index fec2366..52c16c0 100644 --- a/src/ImageCreation/ImageInterface.php +++ b/src/ImageCreation/ImageInterface.php @@ -5,6 +5,8 @@ namespace Assets\ImageCreation; use Assets\Error\ModificationFailedException; +use Intervention\Image\Interfaces as Intervention; +use RuntimeException; interface ImageInterface { @@ -21,4 +23,11 @@ public function save(string $absolutePath, ?int $quality, ?string $format): void * @throws ModificationFailedException */ public function modify(string $modifier, array $params): self; + + public function getInterventionImage(): ?Intervention\ImageInterface; + + /** + * @throws RuntimeException + */ + public function requireInterventionImage(): Intervention\ImageInterface; } diff --git a/src/ImageCreation/Intervention/InterventionImageFacade.php b/src/ImageCreation/Intervention/InterventionImageFacade.php index 190efc0..7e344cb 100644 --- a/src/ImageCreation/Intervention/InterventionImageFacade.php +++ b/src/ImageCreation/Intervention/InterventionImageFacade.php @@ -104,4 +104,14 @@ public function modify(string $modifier, array $params): ImageInterface throw new ModificationFailedException(sprintf('Modifier `%s` does not exist', $modifier)); } + + public function getInterventionImage(): Intervention\ImageInterface + { + return $this->requireInterventionImage(); + } + + public function requireInterventionImage(): Intervention\ImageInterface + { + return $this->interventionImage; + } } From 442afa9734627b875c921a9d914fd23afa819bbf Mon Sep 17 00:00:00 2001 From: passchn <77938819+passchn@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:27:30 +0100 Subject: [PATCH 7/9] [iv3] allow v2 and v3 --- composer.json | 2 +- src/ImageCreation/ImageInterface.php | 9 +- src/ImageCreation/ImageManagerLocator.php | 41 ++++-- .../Intervention/InterventionImageFacade.php | 3 +- .../InterventionImageFacade.php | 117 ++++++++++++++++++ .../InterventionImageManagerFacade.php | 42 +++++++ .../LegacyV2Intervention/LegacySupport.php | 103 +++++++++++++++ 7 files changed, 304 insertions(+), 13 deletions(-) create mode 100644 src/ImageCreation/LegacyV2Intervention/InterventionImageFacade.php create mode 100644 src/ImageCreation/LegacyV2Intervention/InterventionImageManagerFacade.php create mode 100644 src/ImageCreation/LegacyV2Intervention/LegacySupport.php diff --git a/composer.json b/composer.json index b11ef87..5bd1344 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "php": ">=8.2", "ext-fileinfo": "*", "cakephp/cakephp": "^5.1", - "intervention/image": "^3.11", + "intervention/image": "^2 || ^3", "josegonzalez/cakephp-upload": "^8", "league/csv": "^9.8", "nette/utils": "^3.2 || ^4.0.0" diff --git a/src/ImageCreation/ImageInterface.php b/src/ImageCreation/ImageInterface.php index 52c16c0..db1e14f 100644 --- a/src/ImageCreation/ImageInterface.php +++ b/src/ImageCreation/ImageInterface.php @@ -5,7 +5,6 @@ namespace Assets\ImageCreation; use Assets\Error\ModificationFailedException; -use Intervention\Image\Interfaces as Intervention; use RuntimeException; interface ImageInterface @@ -24,10 +23,14 @@ public function save(string $absolutePath, ?int $quality, ?string $format): void */ public function modify(string $modifier, array $params): self; - public function getInterventionImage(): ?Intervention\ImageInterface; + /** + * @return \Intervention\Image\Interfaces\ImageInterface|\Intervention\Image\Image|null + */ + public function getInterventionImage(): ?object; /** + * @return \Intervention\Image\Interfaces\ImageInterface|\Intervention\Image\Image * @throws RuntimeException */ - public function requireInterventionImage(): Intervention\ImageInterface; + public function requireInterventionImage(): object; } diff --git a/src/ImageCreation/ImageManagerLocator.php b/src/ImageCreation/ImageManagerLocator.php index ef12dae..9a2ffc3 100644 --- a/src/ImageCreation/ImageManagerLocator.php +++ b/src/ImageCreation/ImageManagerLocator.php @@ -5,11 +5,13 @@ namespace Assets\ImageCreation; use Assets\ImageCreation\Intervention\InterventionImageManagerFacade; +use Assets\ImageCreation\LegacyV2Intervention as V2; use Assets\ImageCreation\Intervention\LegacySupport; use Cake\Core\Configure; use Intervention\Image\Drivers\Imagick\Driver as ImagickDriver; use Intervention\Image\Drivers\Gd\Driver as GdDriver; use Intervention\Image\ImageManager; +use LogicException; final class ImageManagerLocator { @@ -21,10 +23,40 @@ public static function getImageManager(): ImageManagerInterface return self::$manager; } + if (interface_exists('\Intervention\Image\Interfaces\ImageInterface')) { + return self::$manager = self::createV3ManagerFacade(); + } + + if (class_exists('\Intervention\Image\ImageManager')) { + return self::$manager = self::createV2ManagerFacade(); + } + + throw new LogicException( + 'intervention/image must be installed in v2 or v3', + ); + } + + public static function setImageManager(ImageManagerInterface $manager): void + { + self::$manager = $manager; + } + + private static function createV2ManagerFacade(): ImageManagerInterface + { + $driver = Configure::read('AssetsPlugin.ImageAsset.driver', 'gd'); + + return new V2\InterventionImageManagerFacade( + new ImageManager(['driver' => $driver]), + [], + ); + } + + private static function createV3ManagerFacade(): ImageManagerInterface + { $driver = Configure::read('AssetsPlugin.ImageAsset.driver', 'gd'); $legacyModifiersMap = Configure::read('AssetsPlugin.ImageAsset.legacyModifiersMap'); - return self::$manager = new InterventionImageManagerFacade( + return new InterventionImageManagerFacade( match ($driver) { 'imagick', ImagickDriver::class => ImageManager::imagick( @@ -34,16 +66,11 @@ public static function getImageManager(): ImageManagerInterface GdDriver::class => ImageManager::gd( ...Configure::read('AssetsPlugin.ImageAsset.gdOptions', []), ), - default => throw new \LogicException('no driver configured'), + default => throw new LogicException('no driver configured'), }, legacyModifiersMap: $legacyModifiersMap !== null ? $legacyModifiersMap : LegacySupport::V2_TO_V3_MODIFIERS_MAP, ); } - - public static function setImageManager(ImageManagerInterface $manager): void - { - self::$manager = $manager; - } } diff --git a/src/ImageCreation/Intervention/InterventionImageFacade.php b/src/ImageCreation/Intervention/InterventionImageFacade.php index 7e344cb..5151fc5 100644 --- a/src/ImageCreation/Intervention/InterventionImageFacade.php +++ b/src/ImageCreation/Intervention/InterventionImageFacade.php @@ -19,8 +19,7 @@ final class InterventionImageFacade implements ImageInterface public function __construct( private Intervention\ImageInterface $interventionImage, private array $legacyMdifiersMap, - ) - { + ) { } public function width(): int diff --git a/src/ImageCreation/LegacyV2Intervention/InterventionImageFacade.php b/src/ImageCreation/LegacyV2Intervention/InterventionImageFacade.php new file mode 100644 index 0000000..6f49bcd --- /dev/null +++ b/src/ImageCreation/LegacyV2Intervention/InterventionImageFacade.php @@ -0,0 +1,117 @@ + $legacyMdifiersMap + */ + public function __construct( + private Image $interventionImage, + private array $legacyMdifiersMap, + ) { + } + + public function width(): int + { + return $this->interventionImage->width(); + } + + public function height(): int + { + return $this->interventionImage->height(); + } + + /** + * @see MediaType + */ + public function mime(): string + { + return $this->interventionImage->origin()->mediaType(); + } + + public function save(string $absolutePath, ?int $quality, ?string $format): void + { + if ($format !== null && !str_ends_with($absolutePath, '.' . $format)) { + $absolutePath .= '.' . $format; + } + + $dir = dirname($absolutePath); + + if (!is_dir($dir)) { + FileSystem::createDir($dir); + } + + $this->interventionImage->save($absolutePath, quality: $quality); + } + + public function modify(string $modifier, array $params): ImageInterface + { + if ($params === []) { + throw new ModificationFailedException('Empty params given'); + } + + $modify = function (string $modifier, array $params, ?string $legacyModifier = null) { + try { + $this->interventionImage->{$modifier}(...$params); + } catch (\Throwable $throwable) { + + if ($legacyModifier === null) { + $callback = $this->legacyMdifiersMap[$modifier] ?? null; + if ($callback !== null && is_callable($callback)) { + $callback($this->interventionImage, ...$params); + return $this->interventionImage; + } + } + + throw new ModificationFailedException( + sprintf( + 'Modification `%s` failed with params: %s.%s', + $modifier, + var_export($params, true), + $legacyModifier !== null ? ' Legacy: ' . $legacyModifier : '', + ), + previous: $throwable, + ); + } + }; + + if (method_exists($this->interventionImage, $modifier)) { + $modify($modifier, $params); + return $this; + } + + $mappedFromLegacy = $this->legacyMdifiersMap[$modifier] ?? null; + + if ( + $mappedFromLegacy !== null + && method_exists($this->interventionImage, $mappedFromLegacy) + ) { + $modify($mappedFromLegacy, $params, $modifier); + return $this; + } + + throw new ModificationFailedException(sprintf('Modifier `%s` does not exist', $modifier)); + } + + public function getInterventionImage(): Intervention\ImageInterface + { + return $this->requireInterventionImage(); + } + + public function requireInterventionImage(): Intervention\ImageInterface + { + return $this->interventionImage; + } +} diff --git a/src/ImageCreation/LegacyV2Intervention/InterventionImageManagerFacade.php b/src/ImageCreation/LegacyV2Intervention/InterventionImageManagerFacade.php new file mode 100644 index 0000000..6340ee8 --- /dev/null +++ b/src/ImageCreation/LegacyV2Intervention/InterventionImageManagerFacade.php @@ -0,0 +1,42 @@ + $legacyModifiersMap + */ + public function __construct( + private ImageManager $interventionImageManager, + private array $legacyModifiersMap, + ) { + } + + public function read(string $absolutePath): ImageInterface + { + return new InterventionImageFacade( + $this->interventionImageManager->make($absolutePath), + $this->legacyModifiersMap, + ); + } + + public function create(int $width, int $height): ImageInterface + { + return new InterventionImageFacade( + $this->interventionImageManager->canvas($width, $height), + $this->legacyModifiersMap, + ); + } + + public function canvas(int $width, int $height): ImageInterface + { + return $this->create($width, $height); + } +} diff --git a/src/ImageCreation/LegacyV2Intervention/LegacySupport.php b/src/ImageCreation/LegacyV2Intervention/LegacySupport.php new file mode 100644 index 0000000..29201ec --- /dev/null +++ b/src/ImageCreation/LegacyV2Intervention/LegacySupport.php @@ -0,0 +1,103 @@ + 'create', + 'circle' => 'drawCircle', + 'ellipse' => 'drawEllipse', + 'line' => 'drawLine', + 'pixel' => 'drawPixel', + 'filter' => 'modify', + 'insert' => 'place', + 'make' => 'read', + 'mime' => 'encodedImage', + 'polygon' => 'drawPolygon', + 'rectangle' => 'drawRectangle', + 'limitColors' => 'reduceColors', + 'getCore' => 'core', + 'orientate' => 'orient', + 'widen' => 'scale', + 'heighten' => 'scale', + 'fit' => 'cover', + // Signature changed + 'crop' => [self::class, 'legacyCrop'], + 'encode' => [self::class, 'legacyEncode'], + 'exif' => [self::class, 'legacyExif'], + 'fill' => [self::class, 'legacyFill'], + 'flip' => [self::class, 'legacyFlip'], + 'text' => [self::class, 'legacyText'], + 'resizeCanvas' => [self::class, 'legacyResizeCanvas'], + 'trim' => [self::class, 'legacyTrim'], + 'resize' => [self::class, 'legacyResize'], + ]; + + public static function legacyCrop(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for crop not implemented'); + } + + public static function legacyEncode(Image $image, mixed ...$params): EncodedImageInterface + { + $format = $params[0] ?? null; + + if (!is_string($format)) { + throw new ModificationFailedException('no format given'); + } + + $encoder = new FileExtensionEncoder(FileExtension::from($format)); + + return $image->encode($encoder); + } + + public static function legacyExif(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for exif not implemented'); + } + + public static function legacyFill(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for fill not implemented'); + } + + public static function legacyFlip(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for flip not implemented'); + } + + public static function legacyText(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for text not implemented'); + } + + public static function legacyResizeCanvas(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for resizeCanvas not implemented'); + } + + public static function legacyTrim(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for trim not implemented'); + } + + public static function legacyResize(Image $image, mixed ...$params): Image + { + throw new ModificationFailedException('legacy fallback for resize not implemented'); + } +} From d8bd91e5f6ec91878c7798a0d2b525c75498094f Mon Sep 17 00:00:00 2001 From: passchn <77938819+passchn@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:37:20 +0100 Subject: [PATCH 8/9] [iv3] legacy support adaptions --- src/ImageCreation/ImageManagerLocator.php | 5 +- .../InterventionImageFacade.php | 61 +++++-------------- .../InterventionImageManagerFacade.php | 6 -- 3 files changed, 16 insertions(+), 56 deletions(-) diff --git a/src/ImageCreation/ImageManagerLocator.php b/src/ImageCreation/ImageManagerLocator.php index 9a2ffc3..c69b43e 100644 --- a/src/ImageCreation/ImageManagerLocator.php +++ b/src/ImageCreation/ImageManagerLocator.php @@ -45,10 +45,7 @@ private static function createV2ManagerFacade(): ImageManagerInterface { $driver = Configure::read('AssetsPlugin.ImageAsset.driver', 'gd'); - return new V2\InterventionImageManagerFacade( - new ImageManager(['driver' => $driver]), - [], - ); + return new V2\InterventionImageManagerFacade(new ImageManager(['driver' => $driver])); } private static function createV3ManagerFacade(): ImageManagerInterface diff --git a/src/ImageCreation/LegacyV2Intervention/InterventionImageFacade.php b/src/ImageCreation/LegacyV2Intervention/InterventionImageFacade.php index 6f49bcd..f988cd8 100644 --- a/src/ImageCreation/LegacyV2Intervention/InterventionImageFacade.php +++ b/src/ImageCreation/LegacyV2Intervention/InterventionImageFacade.php @@ -4,23 +4,17 @@ namespace Assets\ImageCreation\LegacyV2Intervention; -use Assets\Error\InvalidArgumentException; use Assets\Error\ModificationFailedException; use Assets\ImageCreation\ImageInterface; use Intervention\Image\Image; use Intervention\Image\MediaType; -use Intervention\Image\Interfaces as Intervention; use Nette\Utils\FileSystem; final class InterventionImageFacade implements ImageInterface { - /** - * @param array $legacyMdifiersMap - */ public function __construct( private Image $interventionImage, - private array $legacyMdifiersMap, - ) { + ) { } public function width(): int @@ -62,55 +56,30 @@ public function modify(string $modifier, array $params): ImageInterface throw new ModificationFailedException('Empty params given'); } - $modify = function (string $modifier, array $params, ?string $legacyModifier = null) { - try { + try { + if (method_exists($this->interventionImage, $modifier)) { $this->interventionImage->{$modifier}(...$params); - } catch (\Throwable $throwable) { - - if ($legacyModifier === null) { - $callback = $this->legacyMdifiersMap[$modifier] ?? null; - if ($callback !== null && is_callable($callback)) { - $callback($this->interventionImage, ...$params); - return $this->interventionImage; - } - } - - throw new ModificationFailedException( - sprintf( - 'Modification `%s` failed with params: %s.%s', - $modifier, - var_export($params, true), - $legacyModifier !== null ? ' Legacy: ' . $legacyModifier : '', - ), - previous: $throwable, - ); } - }; - - if (method_exists($this->interventionImage, $modifier)) { - $modify($modifier, $params); - return $this; - } - - $mappedFromLegacy = $this->legacyMdifiersMap[$modifier] ?? null; - - if ( - $mappedFromLegacy !== null - && method_exists($this->interventionImage, $mappedFromLegacy) - ) { - $modify($mappedFromLegacy, $params, $modifier); - return $this; + } catch (\Throwable $throwable) { + throw new ModificationFailedException( + sprintf( + 'Modification `%s` failed with params: %s.', + $modifier, + var_export($params, true), + ), + previous: $throwable, + ); } throw new ModificationFailedException(sprintf('Modifier `%s` does not exist', $modifier)); } - public function getInterventionImage(): Intervention\ImageInterface + public function getInterventionImage(): Image { - return $this->requireInterventionImage(); + return $this->interventionImage; } - public function requireInterventionImage(): Intervention\ImageInterface + public function requireInterventionImage(): Image { return $this->interventionImage; } diff --git a/src/ImageCreation/LegacyV2Intervention/InterventionImageManagerFacade.php b/src/ImageCreation/LegacyV2Intervention/InterventionImageManagerFacade.php index 6340ee8..4e1a84a 100644 --- a/src/ImageCreation/LegacyV2Intervention/InterventionImageManagerFacade.php +++ b/src/ImageCreation/LegacyV2Intervention/InterventionImageManagerFacade.php @@ -10,12 +10,8 @@ final class InterventionImageManagerFacade implements ImageManagerInterface { - /** - * @param array $legacyModifiersMap - */ public function __construct( private ImageManager $interventionImageManager, - private array $legacyModifiersMap, ) { } @@ -23,7 +19,6 @@ public function read(string $absolutePath): ImageInterface { return new InterventionImageFacade( $this->interventionImageManager->make($absolutePath), - $this->legacyModifiersMap, ); } @@ -31,7 +26,6 @@ public function create(int $width, int $height): ImageInterface { return new InterventionImageFacade( $this->interventionImageManager->canvas($width, $height), - $this->legacyModifiersMap, ); } From a4c23ce9c38dc96f53d5b2d69be21cc61429a361 Mon Sep 17 00:00:00 2001 From: passchn <77938819+passchn@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:43:08 +0100 Subject: [PATCH 9/9] [iv3] improve exception message --- src/Utilities/ImageAsset.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Utilities/ImageAsset.php b/src/Utilities/ImageAsset.php index 302183c..5d2dfb1 100644 --- a/src/Utilities/ImageAsset.php +++ b/src/Utilities/ImageAsset.php @@ -207,7 +207,8 @@ public function applyFilter(string $filter, array $properties = []): self if (!is_a($filter, FilterInterface::class, allow_string: true)) { throw new InvalidArgumentException( sprintf( - 'Argument $filter of type `%s` does not implement `%s`.', + 'Argument $filter (`%s`) of type `%s` does not implement `%s`.', + \Cake\Core\h($filter), get_debug_type($filter), FilterInterface::class, ),