From 302d5d29e96ad70aa7ea147df6392f55f046b00c Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Tue, 10 Sep 2019 17:31:28 +0200 Subject: [PATCH 01/16] !!! TASK: Rename preset to thumbnailPreset This changes the API to make room for future enhancements: - renames `applyPreset()` to `applyThumbnailPreset()` in `ImageSourceHelperInterface` - renames `preset` to `thumbnailPreset` in Fusion prototypes The key `preset` in Fusion is still used if `thumbnailPreset` is not given to provide b/c. --- Classes/EelHelpers/AbstractImageSourceHelper.php | 6 +++--- Classes/EelHelpers/ImageSourceHelperInterface.php | 2 +- .../AbstractImageSourceImplementation.php | 8 ++++---- README.md | 14 +++++++------- .../Fusion/Prototypes/AssetImageSource.fusion | 2 +- .../Fusion/Prototypes/DummyImageSource.fusion | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Classes/EelHelpers/AbstractImageSourceHelper.php b/Classes/EelHelpers/AbstractImageSourceHelper.php index 9687db0..3ae0506 100644 --- a/Classes/EelHelpers/AbstractImageSourceHelper.php +++ b/Classes/EelHelpers/AbstractImageSourceHelper.php @@ -67,12 +67,12 @@ public function setDimensions(int $targetWidth = null, int $targetHeight = null) } /** - * Apply definitions from a preset to this image source + * Apply definitions from a thumbnail preset to this image source * * @param string $name * @return ImageSourceHelperInterface */ - public function applyPreset(string $name): ImageSourceHelperInterface + public function applyThumbnailPreset(string $name): ImageSourceHelperInterface { $newSource = clone $this; if ($this->thumbnailPresets && isset($this->thumbnailPresets[$name])) { @@ -134,7 +134,7 @@ public function srcset($mediaDescriptors): string */ public function allowsCallOfMethod($methodName) { - if (in_array($methodName, ['setWidth', 'setHeight', 'setDimensions', 'applyPreset', 'src', 'srcset'])) { + if (in_array($methodName, ['setWidth', 'setHeight', 'setDimensions', 'applyThumbnailPreset', 'src', 'srcset'])) { return true; } diff --git a/Classes/EelHelpers/ImageSourceHelperInterface.php b/Classes/EelHelpers/ImageSourceHelperInterface.php index 7f75eca..39868e4 100644 --- a/Classes/EelHelpers/ImageSourceHelperInterface.php +++ b/Classes/EelHelpers/ImageSourceHelperInterface.php @@ -13,7 +13,7 @@ public function setHeight(int $height = null, bool $preserveAspect = false): Ima public function setDimensions(int $width = null, int $height = null): ImageSourceHelperInterface; - public function applyPreset(string $name): ImageSourceHelperInterface; + public function applyThumbnailPreset(string $name): ImageSourceHelperInterface; public function src(): string; diff --git a/Classes/FusionObjects/AbstractImageSourceImplementation.php b/Classes/FusionObjects/AbstractImageSourceImplementation.php index 5cea8d7..c0506e2 100644 --- a/Classes/FusionObjects/AbstractImageSourceImplementation.php +++ b/Classes/FusionObjects/AbstractImageSourceImplementation.php @@ -27,9 +27,9 @@ public function getHeight() /** * @return mixed */ - public function getPreset() + public function getThumbnailPreset() { - return $this->fusionValue('preset'); + return $this->fusionValue('thumbnailPreset') ?? $this->fusionValue('preset'); } /** @@ -44,8 +44,8 @@ public function evaluate(): ?ImageSourceHelperInterface return $helper; } - if ($preset = $this->getPreset()) { - $helper = $helper->applyPreset($preset); + if ($preset = $this->getThumbnailPreset()) { + $helper = $helper->applyThumbnailPreset($preset); } if ($width = $this->getWidth()) { diff --git a/README.md b/README.md index b24166b..8c4c622 100644 --- a/README.md +++ b/README.md @@ -224,12 +224,12 @@ The package contains ImageSource-FusionObjects that encapsulate the intention to render an image. ImageSource-Objects return Eel-Helpers that allow to enforcing the rendered dimensions later in the rendering process. -Note: The settings for `width`, `height` and `preset can be defined via fusion +Note: The settings for `width`, `height` and `thumbnailPreset` can be defined via fusion but can also applied on the returned object. This will override the fusion-settings. All ImageSources support the following fusion properties: -- `preset`: Set width and/or height via named-preset from Settings `Neos.Media.thumbnailPresets` (default null, settings below override the preset) +- `thumbnailPreset`: Set width and/or height via named thumbnail preset from Settings `Neos.Media.thumbnailPresets` (default null, settings below override the preset) - `width`: Set the intended width (default null) - `height`: Set the intended height (default null) @@ -239,7 +239,7 @@ Arguments: - `asset`: An image asset that shall be rendered (defaults to the context value `asset`) - `async`: Defer image-rendering until the image is actually requested by the browser (default true) -- `preset`, `width` and `height` are supported as explained above +- `thumbnailPreset`, `width` and `height` are supported as explained above ### `Sitegeist.Kaleidoscope:DummyImageSource` @@ -249,21 +249,21 @@ Arguments: - `backgroundColor`: The background color of the dummy image (default = '999') - `foregroundColor`: The foreground color of the dummy image (default = 'fff') - `text`: The text that is rendered on the image (default = null, show size) -- `preset`, `width` and `height` are supported as explained above +- `thumbnailPreset`, `width` and `height` are supported as explained above ### `Sitegeist.Kaleidoscope:UriImageSource` Arguments: - `uri`: The uri that will be rendered -- !!! `preset`, `width` and `height` have no effect on this ImageSource +- !!! `thumbnailPreset`, `width` and `height` have no effect on this ImageSource ### `Sitegeist.Kaleidoscope:ResourceImageSource` Arguments: - `package`: The package key (e.g. `'My.Package'`) (default = false) - `path`: Path to resource, either a path relative to `Public` and `package` or a `resource://` URI (default = null) -- !!! `preset`, `width` and `height` have no effect on this ImageSource +- !!! `thumbnailPreset`, `width` and `height` have no effect on this ImageSource ## ImageSource EEl-Helpers @@ -273,7 +273,7 @@ dimensions and to render the `src` and `srcset`-attributes. Methods of ImageSource-Helpers that are accessible via EEL: -- `applyPreset( string )`: Set width and/or height via named-preset from Settings `Neos.Media.thumbnailPresets` +- `applyThumbnailPreset( string )`: Set width and/or height via named thumbnail preset from Settings `Neos.Media.thumbnailPresets` - `setWidth( integer $width, bool $preserveAspect = false )`: Set the intend width modify height aswell if - `setHeight( integer $height, bool $preserveAspect = false )`: Set the intended height - `setDimensions( integer, interger)`: Set the intended width and height diff --git a/Resources/Private/Fusion/Prototypes/AssetImageSource.fusion b/Resources/Private/Fusion/Prototypes/AssetImageSource.fusion index 638136e..154ad6d 100644 --- a/Resources/Private/Fusion/Prototypes/AssetImageSource.fusion +++ b/Resources/Private/Fusion/Prototypes/AssetImageSource.fusion @@ -3,7 +3,7 @@ prototype(Sitegeist.Kaleidoscope:AssetImageSource) { asset = ${asset} async = true - preset = null + thumbnailPreset = null width = null height = null } diff --git a/Resources/Private/Fusion/Prototypes/DummyImageSource.fusion b/Resources/Private/Fusion/Prototypes/DummyImageSource.fusion index 6842b92..9b9610f 100644 --- a/Resources/Private/Fusion/Prototypes/DummyImageSource.fusion +++ b/Resources/Private/Fusion/Prototypes/DummyImageSource.fusion @@ -7,7 +7,7 @@ prototype(Sitegeist.Kaleidoscope:DummyImageSource) { foregroundColor = 'fff' text = null - preset = null + thumbnailPreset = null width = null height = null } From 166b4a6254947ac8571809074f20966f2eb7f7f3 Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Tue, 10 Sep 2019 17:33:52 +0200 Subject: [PATCH 02/16] FEATURE: Support for asset variant presets Provides a new property `variantPreset` in the `AssetImageSource` and `DummyImageSource` Fusion prototypes. The expect a string giving the preset identifier and preset variant name separated by `::`, like: Acme.Com:Component.Teaser.Hero::landscape In addition this adds a new method `useVariantPreset()` to the `ImageSourceHelperInterface` that can be used to specify a variant to use based on a configured asset variant preset: useVariantPreset('Acme.Com:Component.Teaser.Hero', 'landscape') That variant (if existing) of an asset will be used as base before any further adjustments are applied. --- Classes/Controller/DummyImageController.php | 100 ++++++++++++++---- .../EelHelpers/AbstractImageSourceHelper.php | 39 ++++++- Classes/EelHelpers/AssetImageSourceHelper.php | 35 +++++- Classes/EelHelpers/DummyImageSourceHelper.php | 4 +- .../EelHelpers/ImageSourceHelperInterface.php | 2 + .../AbstractImageSourceImplementation.php | 17 ++- README.md | 24 +++-- .../Fusion/Prototypes/AssetImageSource.fusion | 1 + .../Fusion/Prototypes/DummyImageSource.fusion | 1 + 9 files changed, 185 insertions(+), 38 deletions(-) diff --git a/Classes/Controller/DummyImageController.php b/Classes/Controller/DummyImageController.php index 0951b49..2f62c23 100644 --- a/Classes/Controller/DummyImageController.php +++ b/Classes/Controller/DummyImageController.php @@ -10,9 +10,17 @@ use Imagine\Image\Palette\Color\ColorInterface; use Imagine\Image\Point; use Neos\Flow\Annotations as Flow; +use Neos\Flow\Log\Utility\LogEnvironment; use Neos\Flow\Mvc\Controller\ActionController; use Neos\Flow\Package\PackageManagerInterface; use Neos\Flow\ResourceManagement\ResourceManager; +use Neos\Media\Domain\Model\Adjustment\ImageAdjustmentInterface; +use Neos\Media\Domain\ValueObject\Configuration\Adjustment; +use Neos\Media\Domain\ValueObject\Configuration\VariantPreset; +use Neos\Media\Exception\AssetVariantGeneratorException; +use Neos\Media\Exception\ImageServiceException; +use Neos\Utility\ObjectAccess; +use Psr\Log\LoggerInterface; class DummyImageController extends ActionController { @@ -34,6 +42,18 @@ class DummyImageController extends ActionController */ protected $packageManager; + /** + * @Flow\Inject + * @var LoggerInterface + */ + protected $logger; + + /** + * @var array + * @Flow\InjectConfiguration(path="variantPresets", package="Neos.Media") + */ + protected $variantPresets; + /** * Get a dummy-image * @@ -42,35 +62,29 @@ class DummyImageController extends ActionController * @param string $bg * @param string $fg * @param string $t + * @param string $pi + * @param string $pv * @return string + * @throws AssetVariantGeneratorException + * @throws ImageServiceException */ - public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', string $fg = '#fff', string $t = null): string + public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', string $fg = '#fff', string $t = null, string $pi = null, string $pv = null): string { // limit input arguments if ($w > 9999) { $w = 9999; + } elseif ($w < 10) { + $w = 10; } if ($h > 9999) { $h = 9999; - } - - // limit input arguments - if ($w < 10) { - $w = 10; - } - - if ($h < 10) { + } elseif ($h < 10) { $h = 10; } - if ($t === null) { - $t = (string)$w . ' x ' . (string)$h; - } - $width = $w; $height = $h; - $text = $t; // create imagine $palette = new Palette\RGB(); @@ -82,15 +96,18 @@ public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', str $image = $this->imagineService->create($imageBox); $image->usePalette($palette); - // render border - $renderBorder = ($w >= 70 && $h >= 70); - - // render shape - $renderShape = ($w >= 200 && $h >= 100); - - $renderText = ($w >= 50 && $h >= 30); + if (isset($this->variantPresets[$pi]['variants'][$pv])) { + $image = $this->applyVariantPresetAdjustments($image, $pi, $pv); + $width = $image->getSize()->getWidth(); + $height = $image->getSize()->getHeight(); + } else { + $this->logger->notice(sprintf('Variant "%s" of preset "%s" is not configured', $pi, $pv), LogEnvironment::fromMethodName(__METHOD__)); + } - $renderPattern = ($w >= 20 && $h >= 20); + $renderBorder = ($width >= 70 && $height >= 70); + $renderShape = ($width >= 200 && $height >= 100); + $renderText = ($width >= 50 && $height >= 30); + $renderPattern = ($width >= 20 && $height >= 20); $this->renderBackground($image, $foregroundColor, $backgroundColor, $width, $height); @@ -102,7 +119,8 @@ public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', str $this->renderBorder($image, $foregroundColor, $backgroundColor, $width, $height); } - if ($t && $renderText) { + if ($renderText) { + $text = trim((string)$t) ?: sprintf('%s x %s', $width, $height); $this->renderText($image, $foregroundColor, $width, $height, $text, $renderShape ? false : true); } @@ -116,6 +134,42 @@ public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', str return $image->get('png'); } + /** + * @param ImageInterface $image + * @param string $pi + * @param string $pv + * @return ImageInterface + * @throws AssetVariantGeneratorException + * @throws ImageServiceException + */ + protected function applyVariantPresetAdjustments(ImageInterface $image, string $pi, string $pv): ImageInterface + { + $assetVariantPreset = VariantPreset::fromConfiguration($this->variantPresets[$pi]); + foreach ($assetVariantPreset->variants()[$pv]->adjustments() as $adjustmentConfiguration) { + assert($adjustmentConfiguration instanceof Adjustment); + $adjustmentClassName = $adjustmentConfiguration->type(); + if (!class_exists($adjustmentClassName)) { + throw new AssetVariantGeneratorException(sprintf('Unknown image variant adjustment type "%s".', $adjustmentClassName), 1568213194); + } + $adjustment = new $adjustmentClassName(); + if (!$adjustment instanceof ImageAdjustmentInterface) { + throw new AssetVariantGeneratorException(sprintf('Image variant adjustment "%s" does not implement "%s".', $adjustmentClassName, ImageAdjustmentInterface::class), 1568213198); + } + foreach ($adjustmentConfiguration->options() as $key => $value) { + ObjectAccess::setProperty($adjustment, $key, $value); + } + + if (!$adjustment instanceof ImageAdjustmentInterface) { + throw new ImageServiceException(sprintf('Could not apply the %s adjustment to image because it does not implement the ImageAdjustmentInterface.', get_class($adjustment)), 1381400362); + } + if ($adjustment->canBeApplied($image)) { + $image = $adjustment->applyToImage($image); + } + } + + return $image; + } + /** * @param ImageInterface $image * @param ColorInterface $foregroundColor diff --git a/Classes/EelHelpers/AbstractImageSourceHelper.php b/Classes/EelHelpers/AbstractImageSourceHelper.php index 3ae0506..c08539a 100644 --- a/Classes/EelHelpers/AbstractImageSourceHelper.php +++ b/Classes/EelHelpers/AbstractImageSourceHelper.php @@ -4,7 +4,9 @@ namespace Sitegeist\Kaleidoscope\EelHelpers; use Neos\Flow\Annotations as Flow; +use Neos\Flow\Log\Utility\LogEnvironment; use Neos\Utility\Arrays; +use Psr\Log\LoggerInterface; /** * Class AbstractImageSourceHelper @@ -23,12 +25,29 @@ abstract class AbstractImageSourceHelper implements ImageSourceHelperInterface */ protected $targetHeight; + /** + * @var array + */ + protected $targetImageVariant = []; + + /** + * @Flow\Inject + * @var LoggerInterface + */ + protected $logger; + /** * @var array * @Flow\InjectConfiguration(path="thumbnailPresets", package="Neos.Media") */ protected $thumbnailPresets; + /** + * @var array + * @Flow\InjectConfiguration(path="variantPresets", package="Neos.Media") + */ + protected $variantPresets; + /** * @param int|null $targetWidth * @param bool $preserveAspect @@ -91,6 +110,24 @@ public function applyThumbnailPreset(string $name): ImageSourceHelperInterface return $newSource; } + /** + * Use the variant generated from the given variant preset in this image source + * + * @param string $presetIdentifier + * @param string $presetVariantName + * @return ImageSourceHelperInterface + */ + public function useVariantPreset(string $presetIdentifier, string $presetVariantName): ImageSourceHelperInterface + { + if (!isset($this->variantPresets[$presetIdentifier]['variants'][$presetVariantName])) { + $this->logger->warning(sprintf('Variant "%s" of preset "%s" is not configured', $presetVariantName, $presetIdentifier), LogEnvironment::fromMethodName(__METHOD__)); + } + + $newSource = clone $this; + $newSource->targetImageVariant = ['presetIdentifier' => $presetIdentifier, 'presetVariantName' => $presetVariantName]; + return $newSource; + } + /** * Render sourceset Attribute for various media descriptors * @@ -134,7 +171,7 @@ public function srcset($mediaDescriptors): string */ public function allowsCallOfMethod($methodName) { - if (in_array($methodName, ['setWidth', 'setHeight', 'setDimensions', 'applyThumbnailPreset', 'src', 'srcset'])) { + if (in_array($methodName, ['setWidth', 'setHeight', 'setDimensions', 'applyThumbnailPreset', 'useVariantPreset', 'src', 'srcset'])) { return true; } diff --git a/Classes/EelHelpers/AssetImageSourceHelper.php b/Classes/EelHelpers/AssetImageSourceHelper.php index 1a7cf43..f7ea909 100644 --- a/Classes/EelHelpers/AssetImageSourceHelper.php +++ b/Classes/EelHelpers/AssetImageSourceHelper.php @@ -6,14 +6,16 @@ use Neos\Flow\Annotations as Flow; use Neos\Flow\Mvc\ActionRequest; use Neos\Media\Domain\Model\AssetInterface; +use Neos\Media\Domain\Model\AssetVariantInterface; use Neos\Media\Domain\Model\ImageInterface; +use Neos\Media\Domain\Model\ImageVariant; use Neos\Media\Domain\Model\ThumbnailConfiguration; +use Neos\Media\Domain\Model\VariantSupportInterface; use Neos\Media\Domain\Service\AssetService; use Neos\Media\Domain\Service\ThumbnailService; class AssetImageSourceHelper extends AbstractScalableImageSourceHelper { - /** * @Flow\Inject * @var ThumbnailService @@ -81,6 +83,11 @@ public function src(): string return ''; } + $assetVariant = null; + if ($this->asset instanceof VariantSupportInterface && $this->targetImageVariant !== []) { + $assetVariant = $this->getAssetVariant($this->asset, $this->targetImageVariant['presetIdentifier'], $this->targetImageVariant['presetVariantName']); + } + $async = $this->request ? $this->async : false; $allowCropping = ($this->targetWidth && $this->targetHeight); $allowUpScaling = false; @@ -96,7 +103,7 @@ public function src(): string ); $thumbnailData = $this->assetService->getThumbnailUriAndSizeForAsset( - $this->asset, + $assetVariant ?? $this->asset, $thumbnailConfiguration, $this->request ); @@ -108,4 +115,28 @@ public function src(): string return $thumbnailData['src']; } + /** + * @param VariantSupportInterface $asset + * @param string $presetIdentifier + * @param string $presetVariantName + * @return ImageVariant + * @todo Remove when getVariant() is available in VariantSupportInterface + */ + private function getAssetVariant(VariantSupportInterface $asset, string $presetIdentifier, string $presetVariantName): ?ImageVariant + { + $variants = $asset->getVariants(); + + if ($variants === []) { + return null; + } + + $variants = array_filter( + $variants, + static function (AssetVariantInterface $variant) use ($presetIdentifier, $presetVariantName) { + return ($variant->getPresetIdentifier() === $presetIdentifier && $variant->getPresetVariantName() === $presetVariantName); + } + ); + + return $variants === [] ? null : current($variants); + } } diff --git a/Classes/EelHelpers/DummyImageSourceHelper.php b/Classes/EelHelpers/DummyImageSourceHelper.php index cad0820..c1b3a7c 100644 --- a/Classes/EelHelpers/DummyImageSourceHelper.php +++ b/Classes/EelHelpers/DummyImageSourceHelper.php @@ -86,7 +86,9 @@ public function src(): string 'h' => $this->getCurrentHeight(), 'bg' => $this->backgroundColor ?: '000', 'fg' => $this->foregroundColor ?: 'fff', - 't' => trim($this->text ?: $this->getCurrentWidth() . ' x ' . $this->getCurrentHeight()) + 't' => trim($this->text ?: $this->getCurrentWidth() . ' x ' . $this->getCurrentHeight()), + 'pi' => $this->targetImageVariant['presetIdentifier'] ?? '', + 'pv' => $this->targetImageVariant['presetVariantName'] ?? '' ] ); } diff --git a/Classes/EelHelpers/ImageSourceHelperInterface.php b/Classes/EelHelpers/ImageSourceHelperInterface.php index 39868e4..f917822 100644 --- a/Classes/EelHelpers/ImageSourceHelperInterface.php +++ b/Classes/EelHelpers/ImageSourceHelperInterface.php @@ -15,6 +15,8 @@ public function setDimensions(int $width = null, int $height = null): ImageSourc public function applyThumbnailPreset(string $name): ImageSourceHelperInterface; + public function useVariantPreset(string $presetIdentifier, string $presetVariantName): ImageSourceHelperInterface; + public function src(): string; public function srcset($mediaDescriptors): string; diff --git a/Classes/FusionObjects/AbstractImageSourceImplementation.php b/Classes/FusionObjects/AbstractImageSourceImplementation.php index c0506e2..e3378ee 100644 --- a/Classes/FusionObjects/AbstractImageSourceImplementation.php +++ b/Classes/FusionObjects/AbstractImageSourceImplementation.php @@ -32,6 +32,14 @@ public function getThumbnailPreset() return $this->fusionValue('thumbnailPreset') ?? $this->fusionValue('preset'); } + /** + * @return mixed + */ + public function getVariantPreset() + { + return $this->fusionValue('variantPreset'); + } + /** * Create helper and initialize width and height * @@ -44,8 +52,13 @@ public function evaluate(): ?ImageSourceHelperInterface return $helper; } - if ($preset = $this->getThumbnailPreset()) { - $helper = $helper->applyThumbnailPreset($preset); + if ($thumbnailPreset = $this->getThumbnailPreset()) { + $helper = $helper->applyThumbnailPreset($thumbnailPreset); + } + + if (($variantPreset = $this->getVariantPreset()) && (strpos($variantPreset, '::') !== false)) { + [$presetIdentifier, $presetVariantName] = explode('::', $variantPreset, 2); + $helper = $helper->useVariantPreset($presetIdentifier, $presetVariantName); } if ($width = $this->getWidth()) { diff --git a/README.md b/README.md index 8c4c622..ad06711 100644 --- a/README.md +++ b/README.md @@ -224,12 +224,13 @@ The package contains ImageSource-FusionObjects that encapsulate the intention to render an image. ImageSource-Objects return Eel-Helpers that allow to enforcing the rendered dimensions later in the rendering process. -Note: The settings for `width`, `height` and `thumbnailPreset` can be defined via fusion -but can also applied on the returned object. This will override the fusion-settings. +Note: The settings for `width`, `height`, `thumbnailPreset` and `variantPreset` can be defined +via fusion but can also applied on the returned object. This will override the fusion-settings. All ImageSources support the following fusion properties: - `thumbnailPreset`: Set width and/or height via named thumbnail preset from Settings `Neos.Media.thumbnailPresets` (default null, settings below override the preset) +- `variantPreset`: Select image variant via named variant preset, given as `IDENTIFIER::VARIANTNAME` keys from Settings `Neos.Media.variantPresets` (default null, settings below override the preset) - `width`: Set the intended width (default null) - `height`: Set the intended height (default null) @@ -239,7 +240,8 @@ Arguments: - `asset`: An image asset that shall be rendered (defaults to the context value `asset`) - `async`: Defer image-rendering until the image is actually requested by the browser (default true) -- `thumbnailPreset`, `width` and `height` are supported as explained above +- `thumbnailPreset`: `width` and `height` are supported as explained above +- `variantPreset`: as explained above ### `Sitegeist.Kaleidoscope:DummyImageSource` @@ -249,21 +251,24 @@ Arguments: - `backgroundColor`: The background color of the dummy image (default = '999') - `foregroundColor`: The foreground color of the dummy image (default = 'fff') - `text`: The text that is rendered on the image (default = null, show size) -- `thumbnailPreset`, `width` and `height` are supported as explained above +- `thumbnailPreset`: `width` and `height` are supported as explained above +- `variantPreset`: as explained above ### `Sitegeist.Kaleidoscope:UriImageSource` Arguments: - `uri`: The uri that will be rendered -- !!! `thumbnailPreset`, `width` and `height` have no effect on this ImageSource +- !!! `thumbnailPreset`: `width` and `height` have no effect on this ImageSource +- !!! `variantPreset`: has no effect on this ImageSource ### `Sitegeist.Kaleidoscope:ResourceImageSource` Arguments: - `package`: The package key (e.g. `'My.Package'`) (default = false) - `path`: Path to resource, either a path relative to `Public` and `package` or a `resource://` URI (default = null) -- !!! `thumbnailPreset`, `width` and `height` have no effect on this ImageSource +- !!! `thumbnailPreset`: `width` and `height` have no effect on this ImageSource +- !!! `variantPreset`: has no effect on this ImageSource ## ImageSource EEl-Helpers @@ -274,11 +279,12 @@ dimensions and to render the `src` and `srcset`-attributes. Methods of ImageSource-Helpers that are accessible via EEL: - `applyThumbnailPreset( string )`: Set width and/or height via named thumbnail preset from Settings `Neos.Media.thumbnailPresets` -- `setWidth( integer $width, bool $preserveAspect = false )`: Set the intend width modify height aswell if +- `useVariantPreset( string, string )`: Select image variant via the named variant preset (parameters are "preset identifier" key and "preset variant name" key from Settings `Neos.Media.variantPresets`) +- `setWidth( integer $width, bool $preserveAspect = false )`: Set the intend width modify height as well if - `setHeight( integer $height, bool $preserveAspect = false )`: Set the intended height - `setDimensions( integer, interger)`: Set the intended width and height -- `src ()` : Render a src attribute for the given ImageSource-object -- `srcset ( array of descriptors )` : render a srcset attribute for the ImageSource with given media descriptors like `2.x` or `800w` +- `src ()`: Render a src attribute for the given ImageSource-object +- `srcset ( array of descriptors )`: render a srcset attribute for the ImageSource with given media descriptors like `2.x` or `800w` Note: The Eel-helpers cannot be created directly. They have to be created by using the `Sitegeist.Kaleidoscope:AssetImageSource` or diff --git a/Resources/Private/Fusion/Prototypes/AssetImageSource.fusion b/Resources/Private/Fusion/Prototypes/AssetImageSource.fusion index 154ad6d..30216a8 100644 --- a/Resources/Private/Fusion/Prototypes/AssetImageSource.fusion +++ b/Resources/Private/Fusion/Prototypes/AssetImageSource.fusion @@ -4,6 +4,7 @@ prototype(Sitegeist.Kaleidoscope:AssetImageSource) { async = true thumbnailPreset = null + variantPreset = null width = null height = null } diff --git a/Resources/Private/Fusion/Prototypes/DummyImageSource.fusion b/Resources/Private/Fusion/Prototypes/DummyImageSource.fusion index 9b9610f..00708e0 100644 --- a/Resources/Private/Fusion/Prototypes/DummyImageSource.fusion +++ b/Resources/Private/Fusion/Prototypes/DummyImageSource.fusion @@ -8,6 +8,7 @@ prototype(Sitegeist.Kaleidoscope:DummyImageSource) { text = null thumbnailPreset = null + variantPreset = null width = null height = null } From a1ba1fb8c79dedfa31a49dba646abb263ba40a3b Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Wed, 11 Sep 2019 17:31:07 +0200 Subject: [PATCH 03/16] TASK: Log requested thumbnail presets if they not configured --- Classes/EelHelpers/AbstractImageSourceHelper.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Classes/EelHelpers/AbstractImageSourceHelper.php b/Classes/EelHelpers/AbstractImageSourceHelper.php index c08539a..117918f 100644 --- a/Classes/EelHelpers/AbstractImageSourceHelper.php +++ b/Classes/EelHelpers/AbstractImageSourceHelper.php @@ -94,7 +94,7 @@ public function setDimensions(int $targetWidth = null, int $targetHeight = null) public function applyThumbnailPreset(string $name): ImageSourceHelperInterface { $newSource = clone $this; - if ($this->thumbnailPresets && isset($this->thumbnailPresets[$name])) { + if (isset($this->thumbnailPresets[$name])) { $preset = $this->thumbnailPresets[$name]; if ($width = $preset['width'] ?? null) { $newSource->setWidth($width); @@ -106,6 +106,8 @@ public function applyThumbnailPreset(string $name): ImageSourceHelperInterface } elseif ($height = $preset['maximumHeight'] ?? null) { $newSource->setHeight($height); } + } else { + $this->logger->warning(sprintf('Thumbnail preset "%s" is not configured', $name), LogEnvironment::fromMethodName(__METHOD__)); } return $newSource; } From 93bf93378323de3fa12ac38ebba42a05c26039ea Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Fri, 13 Sep 2019 11:25:06 +0200 Subject: [PATCH 04/16] TASK: More strict typing --- .../AbstractImageSourceImplementation.php | 16 +++++++-------- .../AssetImageSourceImplementation.php | 15 +++++++------- .../DummyImageSourceImplementation.php | 20 +++++++++---------- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Classes/FusionObjects/AbstractImageSourceImplementation.php b/Classes/FusionObjects/AbstractImageSourceImplementation.php index 68fac36..e0e1f36 100644 --- a/Classes/FusionObjects/AbstractImageSourceImplementation.php +++ b/Classes/FusionObjects/AbstractImageSourceImplementation.php @@ -9,17 +9,17 @@ abstract class AbstractImageSourceImplementation extends AbstractFusionObject { /** - * @return mixed + * @return int|null */ - public function getWidth() + public function getWidth(): ?int { return $this->fusionValue('width'); } /** - * @return mixed + * @return int|null */ - public function getHeight() + public function getHeight(): ?int { return $this->fusionValue('height'); } @@ -33,17 +33,17 @@ public function getFormat(): ?string } /** - * @return mixed + * @return string|null */ - public function getThumbnailPreset() + public function getThumbnailPreset(): ?string { return $this->fusionValue('thumbnailPreset') ?? $this->fusionValue('preset'); } /** - * @return mixed + * @return string|null */ - public function getVariantPreset() + public function getVariantPreset(): ?string { return $this->fusionValue('variantPreset'); } diff --git a/Classes/FusionObjects/AssetImageSourceImplementation.php b/Classes/FusionObjects/AssetImageSourceImplementation.php index 561684b..c3dba8f 100644 --- a/Classes/FusionObjects/AssetImageSourceImplementation.php +++ b/Classes/FusionObjects/AssetImageSourceImplementation.php @@ -5,8 +5,9 @@ use Neos\Flow\Annotations as Flow; use Neos\Flow\ResourceManagement\ResourceManager; -use Sitegeist\Kaleidoscope\EelHelpers\ImageSourceHelperInterface; +use Neos\Media\Domain\Model\ImageInterface; use Sitegeist\Kaleidoscope\EelHelpers\AssetImageSourceHelper; +use Sitegeist\Kaleidoscope\EelHelpers\ImageSourceHelperInterface; use Sitegeist\Kaleidoscope\EelHelpers\UriImageSourceHelper; class AssetImageSourceImplementation extends AbstractImageSourceImplementation @@ -25,17 +26,17 @@ class AssetImageSourceImplementation extends AbstractImageSourceImplementation ]; /** - * @return mixed + * @return ImageInterface|null */ - public function getAsset() + public function getAsset(): ?ImageInterface { return $this->fusionValue('asset'); } /** - * @return mixed + * @return bool|null */ - public function getAsync() + public function getAsync(): ?bool { return $this->fusionValue('async'); } @@ -45,10 +46,10 @@ public function getAsync() * * @return ImageSourceHelperInterface|null */ - public function createHelper() : ?ImageSourceHelperInterface + public function createHelper(): ?ImageSourceHelperInterface { $asset = $this->getAsset(); - if (!$asset) { + if ($asset === null) { return null; } diff --git a/Classes/FusionObjects/DummyImageSourceImplementation.php b/Classes/FusionObjects/DummyImageSourceImplementation.php index 74363ce..19597bb 100644 --- a/Classes/FusionObjects/DummyImageSourceImplementation.php +++ b/Classes/FusionObjects/DummyImageSourceImplementation.php @@ -10,41 +10,41 @@ class DummyImageSourceImplementation extends AbstractImageSourceImplementation { /** - * @return mixed + * @return int|null */ - public function getBaseWidth() + public function getBaseWidth(): ?int { return $this->fusionValue('baseWidth'); } /** - * @return mixed + * @return int|null */ - public function getBaseHeight() + public function getBaseHeight(): ?int { return $this->fusionValue('baseHeight'); } /** - * @return mixed + * @return string|null */ - public function getBackgroundColor() + public function getBackgroundColor(): ?string { return $this->fusionValue('backgroundColor'); } /** - * @return mixed + * @return string|null */ - public function getForegroundColor() + public function getForegroundColor(): ?string { return $this->fusionValue('foregroundColor'); } /** - * @return mixed + * @return string|null */ - public function getText() + public function getText(): ?string { return $this->fusionValue('text'); } From 8f85d63a435c902688dc05ccdba1b54c1660c37b Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Thu, 26 Sep 2019 23:45:45 +0200 Subject: [PATCH 05/16] BUGFIX: Avoid undefined index errors --- Classes/EelHelpers/DummyImageSourceHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/EelHelpers/DummyImageSourceHelper.php b/Classes/EelHelpers/DummyImageSourceHelper.php index b9344fd..ae301db 100644 --- a/Classes/EelHelpers/DummyImageSourceHelper.php +++ b/Classes/EelHelpers/DummyImageSourceHelper.php @@ -101,7 +101,7 @@ public function src(): string $arguments['f'] = $this->targetFormat; } - if ($this->targetImageVariant['presetIdentifier'] && $this->targetImageVariant['presetVariantName']) { + if (isset($this->targetImageVariant['presetIdentifier'], $this->targetImageVariant['presetVariantName'])) { $arguments['pi'] = $this->targetImageVariant['presetIdentifier']; $arguments['pv'] = $this->targetImageVariant['presetVariantName']; } From ffd81eaa24671848a3f373b9d99040e708c83626 Mon Sep 17 00:00:00 2001 From: Martin Ficzel Date: Fri, 27 Sep 2019 17:07:24 +0200 Subject: [PATCH 06/16] TASK: Add deprecated applyPreset methods again for backwards compatibility on eel level --- Classes/EelHelpers/AbstractImageSourceHelper.php | 14 +++++++++++++- Classes/EelHelpers/ImageSourceHelperInterface.php | 7 +++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Classes/EelHelpers/AbstractImageSourceHelper.php b/Classes/EelHelpers/AbstractImageSourceHelper.php index 4efb03f..9a1842e 100644 --- a/Classes/EelHelpers/AbstractImageSourceHelper.php +++ b/Classes/EelHelpers/AbstractImageSourceHelper.php @@ -101,6 +101,18 @@ public function setDimensions(int $targetWidth = null, int $targetHeight = null) return $newSource; } + /** + * DEPRECATED Apply definitions from a thumbnail preset to this image source + * + * @param string $name + * @deprecated use applyThumbnailPreset + * @return ImageSourceHelperInterface + */ + public function applyPreset(string $name): ImageSourceHelperInterface + { + return $this->applyThumbnailPreset($name); + } + /** * Apply definitions from a thumbnail preset to this image source * @@ -189,7 +201,7 @@ public function srcset($mediaDescriptors): string */ public function allowsCallOfMethod($methodName) { - if (in_array($methodName, ['setWidth', 'setHeight', 'setDimensions', 'setFormat', 'applyThumbnailPreset', 'useVariantPreset', 'src', 'srcset'])) { + if (in_array($methodName, ['setWidth', 'setHeight', 'setDimensions', 'setFormat', 'applyPreset', 'applyThumbnailPreset', 'useVariantPreset', 'src', 'srcset'])) { return true; } diff --git a/Classes/EelHelpers/ImageSourceHelperInterface.php b/Classes/EelHelpers/ImageSourceHelperInterface.php index e80ee77..2204aad 100644 --- a/Classes/EelHelpers/ImageSourceHelperInterface.php +++ b/Classes/EelHelpers/ImageSourceHelperInterface.php @@ -15,6 +15,13 @@ public function setDimensions(int $width = null, int $height = null): ImageSourc public function setFormat(string $format = null) : ImageSourceHelperInterface; + /** + * @param string $name + * @deprecated use applyThumbnailPreset + * @return ImageSourceHelperInterface + */ + public function applyPreset(string $name): ImageSourceHelperInterface; + public function applyThumbnailPreset(string $name): ImageSourceHelperInterface; public function useVariantPreset(string $presetIdentifier, string $presetVariantName): ImageSourceHelperInterface; From ad0ebce109aadf61c3aa727f42b8a2d008fb55e7 Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Thu, 3 Oct 2019 10:48:56 +0200 Subject: [PATCH 07/16] BUGFIX: Return changed source in applyThumbnailPreset() --- Classes/EelHelpers/AbstractImageSourceHelper.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Classes/EelHelpers/AbstractImageSourceHelper.php b/Classes/EelHelpers/AbstractImageSourceHelper.php index 9a1842e..d22cd70 100644 --- a/Classes/EelHelpers/AbstractImageSourceHelper.php +++ b/Classes/EelHelpers/AbstractImageSourceHelper.php @@ -125,14 +125,14 @@ public function applyThumbnailPreset(string $name): ImageSourceHelperInterface if (isset($this->thumbnailPresets[$name])) { $preset = $this->thumbnailPresets[$name]; if ($width = $preset['width'] ?? null) { - $newSource->setWidth($width); + $newSource = $newSource->setWidth($width); } elseif ($width = $preset['maximumWidth'] ?? null) { - $newSource->setWidth($width); + $newSource = $newSource->setWidth($width); } if ($height = $preset['height'] ?? null) { - $newSource->setHeight($height); + $newSource = $newSource->setHeight($height); } elseif ($height = $preset['maximumHeight'] ?? null) { - $newSource->setHeight($height); + $newSource = $newSource->setHeight($height); } } else { $this->logger->warning(sprintf('Thumbnail preset "%s" is not configured', $name), LogEnvironment::fromMethodName(__METHOD__)); From c5e5a6a7e1f634e44ea0b2aac737a8fe0eee6a69 Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Thu, 3 Oct 2019 13:21:30 +0200 Subject: [PATCH 08/16] TASK: Properly implement variant preset use in AssetImageSourceHelper This now returns a new source with the asset replaced by the requested variant (if available) and the base dimensions adjusted to that. --- Classes/EelHelpers/AssetImageSourceHelper.php | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/Classes/EelHelpers/AssetImageSourceHelper.php b/Classes/EelHelpers/AssetImageSourceHelper.php index 10ba8b9..5637518 100644 --- a/Classes/EelHelpers/AssetImageSourceHelper.php +++ b/Classes/EelHelpers/AssetImageSourceHelper.php @@ -4,6 +4,7 @@ namespace Sitegeist\Kaleidoscope\EelHelpers; use Neos\Flow\Annotations as Flow; +use Neos\Flow\Log\Utility\LogEnvironment; use Neos\Flow\Mvc\ActionRequest; use Neos\Media\Domain\Model\AssetInterface; use Neos\Media\Domain\Model\AssetVariantInterface; @@ -71,6 +72,34 @@ public function setRequest(ActionRequest $request): void $this->request = $request; } + /** + * Use the variant generated from the given variant preset in this image source + * + * @param string $presetIdentifier + * @param string $presetVariantName + * @return ImageSourceHelperInterface + */ + public function useVariantPreset(string $presetIdentifier, string $presetVariantName): ImageSourceHelperInterface + { + $newSource = parent::useVariantPreset($presetIdentifier, $presetVariantName); + + if ($newSource->targetImageVariant !== []) { + $assetVariant = self::getAssetVariant($newSource->asset, $newSource->targetImageVariant['presetIdentifier'], $newSource->targetImageVariant['presetVariantName']); + if ($assetVariant instanceof ImageVariant) { + $newSource->asset = $assetVariant; + $newSource->baseWidth = $assetVariant->getWidth(); + $newSource->baseHeight = $assetVariant->getHeight(); + } else { + $this->logger->warning( + sprintf('Variant "%s" of preset "%s" not available for image', $newSource->targetImageVariant['presetVariantName'], $newSource->targetImageVariant['presetIdentifier']), + LogEnvironment::fromMethodName(__METHOD__) + ); + } + } + + return $newSource; + } + /** * @return string * @throws \Neos\Flow\Mvc\Routing\Exception\MissingActionNameException @@ -83,11 +112,6 @@ public function src(): string return ''; } - $assetVariant = null; - if ($this->asset instanceof VariantSupportInterface && $this->targetImageVariant !== []) { - $assetVariant = $this->getAssetVariant($this->asset, $this->targetImageVariant['presetIdentifier'], $this->targetImageVariant['presetVariantName']); - } - $async = $this->request ? $this->async : false; $allowCropping = ($this->targetWidth && $this->targetHeight); $allowUpScaling = false; @@ -104,7 +128,7 @@ public function src(): string ); $thumbnailData = $this->assetService->getThumbnailUriAndSizeForAsset( - $assetVariant ?? $this->asset, + $this->asset, $thumbnailConfiguration, $this->request ); @@ -123,7 +147,7 @@ public function src(): string * @return ImageVariant * @todo Remove when getVariant() is available in VariantSupportInterface */ - private function getAssetVariant(VariantSupportInterface $asset, string $presetIdentifier, string $presetVariantName): ?ImageVariant + private static function getAssetVariant(VariantSupportInterface $asset, string $presetIdentifier, string $presetVariantName): ?ImageVariant { $variants = $asset->getVariants(); From 6cfb98120b8367bf0d0beff65a3d21e2557176a4 Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Thu, 3 Oct 2019 13:35:09 +0200 Subject: [PATCH 09/16] TASK: Properly implement variant preset use in DummyImageSourceHelper This now returns a new source with base dimensions adjusted as needed. --- Classes/EelHelpers/DummyImageSourceHelper.php | 105 +++++++++++++++++- 1 file changed, 101 insertions(+), 4 deletions(-) diff --git a/Classes/EelHelpers/DummyImageSourceHelper.php b/Classes/EelHelpers/DummyImageSourceHelper.php index 384078e..39be723 100644 --- a/Classes/EelHelpers/DummyImageSourceHelper.php +++ b/Classes/EelHelpers/DummyImageSourceHelper.php @@ -3,8 +3,24 @@ namespace Sitegeist\Kaleidoscope\EelHelpers; +use Imagine\Image\Box; +use Imagine\Image\ImagineInterface; +use Neos\Flow\Annotations as Flow; +use Neos\Media\Domain\Model\Adjustment\CropImageAdjustment; +use Neos\Media\Domain\Model\Adjustment\ImageAdjustmentInterface; +use Neos\Media\Domain\Model\Adjustment\ResizeImageAdjustment; +use Neos\Media\Domain\ValueObject\Configuration\Adjustment; +use Neos\Media\Domain\ValueObject\Configuration\VariantPreset; +use Neos\Utility\ObjectAccess; + class DummyImageSourceHelper extends AbstractScalableImageSourceHelper { + /** + * @var ImagineInterface + * @Flow\Inject + */ + protected $imagineService; + /** * @var string */ @@ -75,6 +91,25 @@ public function setText($text): void $this->text = $text; } + /** + * Use the variant generated from the given variant preset in this image source + * + * @param string $presetIdentifier + * @param string $presetVariantName + * @return ImageSourceHelperInterface + */ + public function useVariantPreset(string $presetIdentifier, string $presetVariantName): ImageSourceHelperInterface + { + /** @var DummyImageSourceHelper $newSource */ + $newSource = parent::useVariantPreset($presetIdentifier, $presetVariantName); + + if ($newSource->targetImageVariant !== []) { + $newSource = $this->calculateSizeFromVariantPresetAdjustments($newSource); + } + + return $newSource; + } + /** * @return string */ @@ -101,11 +136,73 @@ public function src(): string $arguments['f'] = $this->targetFormat; } - if (isset($this->targetImageVariant['presetIdentifier'], $this->targetImageVariant['presetVariantName'])) { - $arguments['pi'] = $this->targetImageVariant['presetIdentifier']; - $arguments['pv'] = $this->targetImageVariant['presetVariantName']; + return $this->baseUri . '?' . http_build_query($arguments); + } + + /** + * @param DummyImageSourceHelper $source + * @return ImageSourceHelperInterface + * @throws \RuntimeException + */ + protected function calculateSizeFromVariantPresetAdjustments(DummyImageSourceHelper $source): ImageSourceHelperInterface + { + $presetIdentifier = $source->targetImageVariant['presetIdentifier']; + $presetVariantName = $source->targetImageVariant['presetVariantName']; + + $assetVariantPreset = VariantPreset::fromConfiguration($this->variantPresets[$presetIdentifier]); + foreach ($assetVariantPreset->variants()[$presetVariantName]->adjustments() as $adjustmentConfiguration) { + $adjustment = $this->createAdjustment($adjustmentConfiguration); + + switch (true) { + case ($adjustment instanceof ResizeImageAdjustment): + $imageBox = new Box($source->baseWidth, $$source->baseHeight); + $image = $this->imagineService->create($imageBox); + if ($adjustment->canBeApplied($image)) { + $image = $adjustment->applyToImage($image); + $source->baseWidth = $image->getSize()->getWidth(); + $source->baseHeight = $image->getSize()->getHeight(); + } + break; + case ($adjustment instanceof CropImageAdjustment): + $desiredAspectRatio = $adjustment->getAspectRatio(); + if ($desiredAspectRatio !== null) { + [, , $newWidth, $newHeight] = CropImageAdjustment::calculateDimensionsByAspectRatio($source->baseWidth, $source->baseHeight, $desiredAspectRatio); + } else { + $newWidth = $adjustment->getWidth(); + $newHeight = $adjustment->getHeight(); + } + + $source->baseWidth = $newWidth; + $source->baseHeight = $newHeight; + break; + } + } + + return $source; + } + + /** + * @param Adjustment $adjustmentConfiguration + * @return ImageAdjustmentInterface + */ + protected function createAdjustment(Adjustment $adjustmentConfiguration): ImageAdjustmentInterface + { + $adjustmentClassName = $adjustmentConfiguration->type(); + if (!class_exists($adjustmentClassName)) { + throw new \RuntimeException(sprintf('Unknown image variant adjustment type "%s".', $adjustmentClassName), 1568213194); + } + $adjustment = new $adjustmentClassName(); + if (!$adjustment instanceof ImageAdjustmentInterface) { + throw new \RuntimeException(sprintf('Image variant adjustment "%s" does not implement "%s".', $adjustmentClassName, ImageAdjustmentInterface::class), 1568213198); + } + foreach ($adjustmentConfiguration->options() as $key => $value) { + ObjectAccess::setProperty($adjustment, $key, $value); } - return $this->baseUri . '?' . http_build_query($arguments); + if (!$adjustment instanceof ImageAdjustmentInterface) { + throw new \RuntimeException(sprintf('Could not apply the %s adjustment to image because it does not implement the ImageAdjustmentInterface.', get_class($adjustment)), 1381400362); + } + + return $adjustment; } } From 52afc46f25ddf293d8f08d8226b8fb22adeee921 Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Thu, 3 Oct 2019 13:18:50 +0200 Subject: [PATCH 10/16] TASK: Remove variant preset handling from DummyImageController --- Classes/Controller/DummyImageController.php | 61 +-------------------- 1 file changed, 3 insertions(+), 58 deletions(-) diff --git a/Classes/Controller/DummyImageController.php b/Classes/Controller/DummyImageController.php index e33e51a..d7bc62f 100644 --- a/Classes/Controller/DummyImageController.php +++ b/Classes/Controller/DummyImageController.php @@ -12,14 +12,9 @@ use Neos\Flow\Annotations as Flow; use Neos\Flow\Log\Utility\LogEnvironment; use Neos\Flow\Mvc\Controller\ActionController; +use Neos\Flow\Package\Exception\UnknownPackageException; use Neos\Flow\Package\PackageManager; use Neos\Flow\ResourceManagement\ResourceManager; -use Neos\Media\Domain\Model\Adjustment\ImageAdjustmentInterface; -use Neos\Media\Domain\ValueObject\Configuration\Adjustment; -use Neos\Media\Domain\ValueObject\Configuration\VariantPreset; -use Neos\Media\Exception\AssetVariantGeneratorException; -use Neos\Media\Exception\ImageServiceException; -use Neos\Utility\ObjectAccess; use Psr\Log\LoggerInterface; class DummyImageController extends ActionController @@ -48,12 +43,6 @@ class DummyImageController extends ActionController */ protected $logger; - /** - * @var array - * @Flow\InjectConfiguration(path="variantPresets", package="Neos.Media") - */ - protected $variantPresets; - /** * Get a dummy-image * @@ -95,15 +84,6 @@ public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', str $image = $this->imagineService->create($imageBox); $image->usePalette($palette); - // create imagine - if (isset($this->variantPresets[$pi]['variants'][$pv])) { - $image = $this->applyVariantPresetAdjustments($image, $pi, $pv); - $width = $image->getSize()->getWidth(); - $height = $image->getSize()->getHeight(); - } else { - $this->logger->notice(sprintf('Variant "%s" of preset "%s" is not configured', $pi, $pv), LogEnvironment::fromMethodName(__METHOD__)); - } - $renderBorder = ($width >= 70 && $height >= 70); $renderShape = ($width >= 200 && $height >= 100); $renderText = ($width >= 50 && $height >= 30); @@ -131,7 +111,7 @@ public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', str // render image $result = $image->get($f); if (!$result) { - throw new \Exception('Something went wrong without throwing an exception'); + throw new \RuntimeException('Something went wrong without throwing an exception'); } // build result @@ -148,42 +128,6 @@ public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', str } } - /** - * @param ImageInterface $image - * @param string $pi - * @param string $pv - * @return ImageInterface - * @throws AssetVariantGeneratorException - * @throws ImageServiceException - */ - protected function applyVariantPresetAdjustments(ImageInterface $image, string $pi, string $pv): ImageInterface - { - $assetVariantPreset = VariantPreset::fromConfiguration($this->variantPresets[$pi]); - foreach ($assetVariantPreset->variants()[$pv]->adjustments() as $adjustmentConfiguration) { - assert($adjustmentConfiguration instanceof Adjustment); - $adjustmentClassName = $adjustmentConfiguration->type(); - if (!class_exists($adjustmentClassName)) { - throw new AssetVariantGeneratorException(sprintf('Unknown image variant adjustment type "%s".', $adjustmentClassName), 1568213194); - } - $adjustment = new $adjustmentClassName(); - if (!$adjustment instanceof ImageAdjustmentInterface) { - throw new AssetVariantGeneratorException(sprintf('Image variant adjustment "%s" does not implement "%s".', $adjustmentClassName, ImageAdjustmentInterface::class), 1568213198); - } - foreach ($adjustmentConfiguration->options() as $key => $value) { - ObjectAccess::setProperty($adjustment, $key, $value); - } - - if (!$adjustment instanceof ImageAdjustmentInterface) { - throw new ImageServiceException(sprintf('Could not apply the %s adjustment to image because it does not implement the ImageAdjustmentInterface.', get_class($adjustment)), 1381400362); - } - if ($adjustment->canBeApplied($image)) { - $image = $adjustment->applyToImage($image); - } - } - - return $image; - } - /** * @param ImageInterface $image * @param ColorInterface $foregroundColor @@ -304,6 +248,7 @@ protected function renderBorder(ImageInterface $image, ColorInterface $foregroun * @param int $height * @param string $text * @param bool $center + * @throws UnknownPackageException */ protected function renderText(ImageInterface $image, ColorInterface $textColor, int $width, int $height, string $text, bool $center = false): void { From a446112095715013fe951c0180c9c5278b121dfe Mon Sep 17 00:00:00 2001 From: Karsten Dambekalns Date: Thu, 24 Oct 2019 18:18:20 +0200 Subject: [PATCH 11/16] TASK: Make sure variants are fetched from Image, not ImageVariant In case the given asset is already a variant (e.g. because crop has been applied manually), try to fetch a variant preset based on the original asset of the given variant. --- Classes/EelHelpers/AssetImageSourceHelper.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/EelHelpers/AssetImageSourceHelper.php b/Classes/EelHelpers/AssetImageSourceHelper.php index 5637518..1533288 100644 --- a/Classes/EelHelpers/AssetImageSourceHelper.php +++ b/Classes/EelHelpers/AssetImageSourceHelper.php @@ -84,7 +84,8 @@ public function useVariantPreset(string $presetIdentifier, string $presetVariant $newSource = parent::useVariantPreset($presetIdentifier, $presetVariantName); if ($newSource->targetImageVariant !== []) { - $assetVariant = self::getAssetVariant($newSource->asset, $newSource->targetImageVariant['presetIdentifier'], $newSource->targetImageVariant['presetVariantName']); + $asset = ($newSource->asset instanceof ImageVariant) ? $newSource->asset->getOriginalAsset() : $newSource->asset; + $assetVariant = self::getAssetVariant($asset, $newSource->targetImageVariant['presetIdentifier'], $newSource->targetImageVariant['presetVariantName']); if ($assetVariant instanceof ImageVariant) { $newSource->asset = $assetVariant; $newSource->baseWidth = $assetVariant->getWidth(); From e76b55cef2dfebdd42fee4bb4bbe87d12cfdc751 Mon Sep 17 00:00:00 2001 From: Martin Ficzel Date: Mon, 28 Oct 2019 10:10:31 +0100 Subject: [PATCH 12/16] BUGFIX: Remove leftover parameters from dummy image controller --- Classes/Controller/DummyImageController.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Classes/Controller/DummyImageController.php b/Classes/Controller/DummyImageController.php index d7bc62f..a1e9288 100644 --- a/Classes/Controller/DummyImageController.php +++ b/Classes/Controller/DummyImageController.php @@ -52,11 +52,9 @@ class DummyImageController extends ActionController * @param string $fg * @param string $t * @param string $f - * @param string $pi - * @param string $pv * @return string */ - public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', string $fg = '#fff', string $t = null, string $f = 'png', string $pi = null, string $pv = null): string + public function imageAction(int $w = 600, int $h = 400, string $bg = '#000', string $fg = '#fff', string $t = null, string $f = 'png'): string { // limit input arguments if ($w > 9999) { From 840365841fe0bdb8c8569d683da6a3c129877bf5 Mon Sep 17 00:00:00 2001 From: Martin Ficzel Date: Mon, 28 Oct 2019 10:12:55 +0100 Subject: [PATCH 13/16] BUGFIX: Calculate dimensions of dummy images properly Ensure the calculated values are of type integer. --- Classes/EelHelpers/DummyImageSourceHelper.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Classes/EelHelpers/DummyImageSourceHelper.php b/Classes/EelHelpers/DummyImageSourceHelper.php index 39be723..7e24d1d 100644 --- a/Classes/EelHelpers/DummyImageSourceHelper.php +++ b/Classes/EelHelpers/DummyImageSourceHelper.php @@ -155,12 +155,12 @@ protected function calculateSizeFromVariantPresetAdjustments(DummyImageSourceHel switch (true) { case ($adjustment instanceof ResizeImageAdjustment): - $imageBox = new Box($source->baseWidth, $$source->baseHeight); + $imageBox = new Box($source->baseWidth, $source->baseHeight); $image = $this->imagineService->create($imageBox); if ($adjustment->canBeApplied($image)) { $image = $adjustment->applyToImage($image); - $source->baseWidth = $image->getSize()->getWidth(); - $source->baseHeight = $image->getSize()->getHeight(); + $source->baseWidth = (int)round($image->getSize()->getWidth()); + $source->baseHeight = (int)round($image->getSize()->getHeight()); } break; case ($adjustment instanceof CropImageAdjustment): @@ -172,8 +172,8 @@ protected function calculateSizeFromVariantPresetAdjustments(DummyImageSourceHel $newHeight = $adjustment->getHeight(); } - $source->baseWidth = $newWidth; - $source->baseHeight = $newHeight; + $source->baseWidth = (int)round($newWidth); + $source->baseHeight = (int)round($newHeight); break; } } From fa6b3e71b20dc0f5b8622132ea4dbbde3af9c7e6 Mon Sep 17 00:00:00 2001 From: Martin Ficzel Date: Mon, 28 Oct 2019 13:22:59 +0100 Subject: [PATCH 14/16] TASK: Use fallback dimension setting if no variant was found --- .../AbstractScalableImageSourceHelper.php | 86 +++++++++++++++++++ Classes/EelHelpers/AssetImageSourceHelper.php | 8 +- Classes/EelHelpers/DummyImageSourceHelper.php | 86 +------------------ 3 files changed, 93 insertions(+), 87 deletions(-) diff --git a/Classes/EelHelpers/AbstractScalableImageSourceHelper.php b/Classes/EelHelpers/AbstractScalableImageSourceHelper.php index 8c6c9d2..6a3bea9 100644 --- a/Classes/EelHelpers/AbstractScalableImageSourceHelper.php +++ b/Classes/EelHelpers/AbstractScalableImageSourceHelper.php @@ -3,8 +3,24 @@ namespace Sitegeist\Kaleidoscope\EelHelpers; +use Imagine\Image\Box; +use Imagine\Image\ImagineInterface; +use Neos\Flow\Annotations as Flow; +use Neos\Media\Domain\ValueObject\Configuration\VariantPreset; +use Neos\Media\Domain\Model\Adjustment\ImageAdjustmentInterface; +use Neos\Media\Domain\Model\Adjustment\ResizeImageAdjustment; +use Neos\Media\Domain\Model\Adjustment\CropImageAdjustment; +use Neos\Media\Domain\ValueObject\Configuration\Adjustment; +use Neos\Utility\ObjectAccess; + abstract class AbstractScalableImageSourceHelper extends AbstractImageSourceHelper implements ScalableImageSourceHelperInterface { + /** + * @var ImagineInterface + * @Flow\Inject + */ + protected $imagineService; + /** * @var int */ @@ -100,4 +116,74 @@ public function getCurrentHeight(): int return $this->baseHeight; } + /** + * @param string $presetIdentifier + * @param string $presetVariantName + * @return Box + */ + protected function estimateDimensionsFromVariantPresetAdjustments(string $presetIdentifier, string $presetVariantName): Box + { + $imageBox = new Box( + $this->baseWidth, + $this->baseHeight + ); + + $assetVariantPreset = VariantPreset::fromConfiguration($this->variantPresets[$presetIdentifier]); + foreach ($assetVariantPreset->variants()[$presetVariantName]->adjustments() as $adjustmentConfiguration) { + $adjustment = $this->createAdjustment($adjustmentConfiguration); + + switch (true) { + case ($adjustment instanceof ResizeImageAdjustment): + $image = $this->imagineService->create($imageBox); + if ($adjustment->canBeApplied($image)) { + $image = $adjustment->applyToImage($image); + return new Box( + (int)round($image->getSize()->getWidth()), + (int)round($image->getSize()->getHeight()) + ); + } + break; + case ($adjustment instanceof CropImageAdjustment): + $desiredAspectRatio = $adjustment->getAspectRatio(); + if ($desiredAspectRatio !== null) { + [, , $newWidth, $newHeight] = CropImageAdjustment::calculateDimensionsByAspectRatio($this->baseWidth, $this->baseHeight, $desiredAspectRatio); + } else { + $newWidth = $adjustment->getWidth(); + $newHeight = $adjustment->getHeight(); + } + return new Box( + (int)round($newWidth), + (int)round($newHeight) + ); + break; + } + } + + return $imageBox; + } + + /** + * @param Adjustment $adjustmentConfiguration + * @return ImageAdjustmentInterface + */ + protected function createAdjustment(Adjustment $adjustmentConfiguration): ImageAdjustmentInterface + { + $adjustmentClassName = $adjustmentConfiguration->type(); + if (!class_exists($adjustmentClassName)) { + throw new \RuntimeException(sprintf('Unknown image variant adjustment type "%s".', $adjustmentClassName), 1568213194); + } + $adjustment = new $adjustmentClassName(); + if (!$adjustment instanceof ImageAdjustmentInterface) { + throw new \RuntimeException(sprintf('Image variant adjustment "%s" does not implement "%s".', $adjustmentClassName, ImageAdjustmentInterface::class), 1568213198); + } + foreach ($adjustmentConfiguration->options() as $key => $value) { + ObjectAccess::setProperty($adjustment, $key, $value); + } + + if (!$adjustment instanceof ImageAdjustmentInterface) { + throw new \RuntimeException(sprintf('Could not apply the %s adjustment to image because it does not implement the ImageAdjustmentInterface.', get_class($adjustment)), 1381400362); + } + + return $adjustment; + } } diff --git a/Classes/EelHelpers/AssetImageSourceHelper.php b/Classes/EelHelpers/AssetImageSourceHelper.php index 1533288..4879fbd 100644 --- a/Classes/EelHelpers/AssetImageSourceHelper.php +++ b/Classes/EelHelpers/AssetImageSourceHelper.php @@ -91,10 +91,10 @@ public function useVariantPreset(string $presetIdentifier, string $presetVariant $newSource->baseWidth = $assetVariant->getWidth(); $newSource->baseHeight = $assetVariant->getHeight(); } else { - $this->logger->warning( - sprintf('Variant "%s" of preset "%s" not available for image', $newSource->targetImageVariant['presetVariantName'], $newSource->targetImageVariant['presetIdentifier']), - LogEnvironment::fromMethodName(__METHOD__) - ); + // if no alternate variant is found we estimate the target dimensions + $targetDimensions = $this->estimateDimensionsFromVariantPresetAdjustments($presetIdentifier, $presetVariantName); + $newSource->targetWidth = $targetDimensions->getWidth(); + $newSource->targetHeight = $targetDimensions->getHeight(); } } diff --git a/Classes/EelHelpers/DummyImageSourceHelper.php b/Classes/EelHelpers/DummyImageSourceHelper.php index 7e24d1d..d07e7e1 100644 --- a/Classes/EelHelpers/DummyImageSourceHelper.php +++ b/Classes/EelHelpers/DummyImageSourceHelper.php @@ -3,24 +3,8 @@ namespace Sitegeist\Kaleidoscope\EelHelpers; -use Imagine\Image\Box; -use Imagine\Image\ImagineInterface; -use Neos\Flow\Annotations as Flow; -use Neos\Media\Domain\Model\Adjustment\CropImageAdjustment; -use Neos\Media\Domain\Model\Adjustment\ImageAdjustmentInterface; -use Neos\Media\Domain\Model\Adjustment\ResizeImageAdjustment; -use Neos\Media\Domain\ValueObject\Configuration\Adjustment; -use Neos\Media\Domain\ValueObject\Configuration\VariantPreset; -use Neos\Utility\ObjectAccess; - class DummyImageSourceHelper extends AbstractScalableImageSourceHelper { - /** - * @var ImagineInterface - * @Flow\Inject - */ - protected $imagineService; - /** * @var string */ @@ -104,7 +88,9 @@ public function useVariantPreset(string $presetIdentifier, string $presetVariant $newSource = parent::useVariantPreset($presetIdentifier, $presetVariantName); if ($newSource->targetImageVariant !== []) { - $newSource = $this->calculateSizeFromVariantPresetAdjustments($newSource); + $targetBox = $this->estimateDimensionsFromVariantPresetAdjustments($presetIdentifier, $presetVariantName); + $newSource->baseWidth = $targetBox->getWidth(); + $newSource->baseHeight = $targetBox->getHeight(); } return $newSource; @@ -139,70 +125,4 @@ public function src(): string return $this->baseUri . '?' . http_build_query($arguments); } - /** - * @param DummyImageSourceHelper $source - * @return ImageSourceHelperInterface - * @throws \RuntimeException - */ - protected function calculateSizeFromVariantPresetAdjustments(DummyImageSourceHelper $source): ImageSourceHelperInterface - { - $presetIdentifier = $source->targetImageVariant['presetIdentifier']; - $presetVariantName = $source->targetImageVariant['presetVariantName']; - - $assetVariantPreset = VariantPreset::fromConfiguration($this->variantPresets[$presetIdentifier]); - foreach ($assetVariantPreset->variants()[$presetVariantName]->adjustments() as $adjustmentConfiguration) { - $adjustment = $this->createAdjustment($adjustmentConfiguration); - - switch (true) { - case ($adjustment instanceof ResizeImageAdjustment): - $imageBox = new Box($source->baseWidth, $source->baseHeight); - $image = $this->imagineService->create($imageBox); - if ($adjustment->canBeApplied($image)) { - $image = $adjustment->applyToImage($image); - $source->baseWidth = (int)round($image->getSize()->getWidth()); - $source->baseHeight = (int)round($image->getSize()->getHeight()); - } - break; - case ($adjustment instanceof CropImageAdjustment): - $desiredAspectRatio = $adjustment->getAspectRatio(); - if ($desiredAspectRatio !== null) { - [, , $newWidth, $newHeight] = CropImageAdjustment::calculateDimensionsByAspectRatio($source->baseWidth, $source->baseHeight, $desiredAspectRatio); - } else { - $newWidth = $adjustment->getWidth(); - $newHeight = $adjustment->getHeight(); - } - - $source->baseWidth = (int)round($newWidth); - $source->baseHeight = (int)round($newHeight); - break; - } - } - - return $source; - } - - /** - * @param Adjustment $adjustmentConfiguration - * @return ImageAdjustmentInterface - */ - protected function createAdjustment(Adjustment $adjustmentConfiguration): ImageAdjustmentInterface - { - $adjustmentClassName = $adjustmentConfiguration->type(); - if (!class_exists($adjustmentClassName)) { - throw new \RuntimeException(sprintf('Unknown image variant adjustment type "%s".', $adjustmentClassName), 1568213194); - } - $adjustment = new $adjustmentClassName(); - if (!$adjustment instanceof ImageAdjustmentInterface) { - throw new \RuntimeException(sprintf('Image variant adjustment "%s" does not implement "%s".', $adjustmentClassName, ImageAdjustmentInterface::class), 1568213198); - } - foreach ($adjustmentConfiguration->options() as $key => $value) { - ObjectAccess::setProperty($adjustment, $key, $value); - } - - if (!$adjustment instanceof ImageAdjustmentInterface) { - throw new \RuntimeException(sprintf('Could not apply the %s adjustment to image because it does not implement the ImageAdjustmentInterface.', get_class($adjustment)), 1381400362); - } - - return $adjustment; - } } From 30dfee3ca517c26c323faf3edf99fddfe53106ff Mon Sep 17 00:00:00 2001 From: Martin Ficzel Date: Mon, 28 Oct 2019 14:05:14 +0100 Subject: [PATCH 15/16] TASK: Use baseWidth and baseHeight for assignment of dimensions The calculation of the asset image src has to be adjusted for that to explicitly calculate width and height. --- Classes/EelHelpers/AssetImageSourceHelper.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Classes/EelHelpers/AssetImageSourceHelper.php b/Classes/EelHelpers/AssetImageSourceHelper.php index 4879fbd..a9a7a58 100644 --- a/Classes/EelHelpers/AssetImageSourceHelper.php +++ b/Classes/EelHelpers/AssetImageSourceHelper.php @@ -93,8 +93,8 @@ public function useVariantPreset(string $presetIdentifier, string $presetVariant } else { // if no alternate variant is found we estimate the target dimensions $targetDimensions = $this->estimateDimensionsFromVariantPresetAdjustments($presetIdentifier, $presetVariantName); - $newSource->targetWidth = $targetDimensions->getWidth(); - $newSource->targetHeight = $targetDimensions->getHeight(); + $newSource->baseWidth = $targetDimensions->getWidth(); + $newSource->baseHeight = $targetDimensions->getHeight(); } } @@ -113,14 +113,17 @@ public function src(): string return ''; } + $width = $this->getCurrentWidth(); + $height = $this->getCurrentHeight(); + $async = $this->request ? $this->async : false; - $allowCropping = ($this->targetWidth && $this->targetHeight); + $allowCropping = true; $allowUpScaling = false; $thumbnailConfiguration = new ThumbnailConfiguration( - $this->targetWidth, - $this->targetWidth, - $this->targetHeight, - $this->targetHeight, + $width, + $width, + $height, + $height, $allowCropping, $allowUpScaling, $async, From d632a5656419e643492a5dfed6e63eb31864524f Mon Sep 17 00:00:00 2001 From: Martin Ficzel Date: Tue, 29 Oct 2019 14:56:53 +0100 Subject: [PATCH 16/16] FEATURE: Support passing-content into Sitegeist.Kaleidoscope:Picture This is handy for defining sources via Sitegeist.Kaleidoscope:Source in afx --- Resources/Private/Fusion/Prototypes/Picture.fusion | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Private/Fusion/Prototypes/Picture.fusion b/Resources/Private/Fusion/Prototypes/Picture.fusion index 05a497a..d00fe2f 100644 --- a/Resources/Private/Fusion/Prototypes/Picture.fusion +++ b/Resources/Private/Fusion/Prototypes/Picture.fusion @@ -36,9 +36,11 @@ prototype(Sitegeist.Kaleidoscope:Picture) < prototype(Neos.Fusion:Component) { alt = null title = null class = null + content = '' renderer = afx` + {props.content}