diff --git a/Classes/Domain/Model/PictureConfiguration.php b/Classes/Domain/Model/PictureConfiguration.php index d4a9bf9..428c75e 100644 --- a/Classes/Domain/Model/PictureConfiguration.php +++ b/Classes/Domain/Model/PictureConfiguration.php @@ -51,10 +51,6 @@ public function __construct(array $arguments, array $typoScriptSettings, FileInt $this->sources = $arguments['sources']; $this->addSources = true; } - if (!empty($typoScriptSettings['lazyLoading']) && !isset($arguments['loading'])) { - $this->addLazyLoading = true; - $this->lazyLoading = (string)$typoScriptSettings['lazyLoading']; - } // do not add retina images for elements with variants (the browser should select the best-sized image) if (!empty($arguments['sizes'])) { $this->useRetina = false; @@ -63,6 +59,10 @@ public function __construct(array $arguments, array $typoScriptSettings, FileInt if (isset($arguments['pictureClass'])) { $this->pictureClass = $arguments['pictureClass']; } + if (!empty($typoScriptSettings['lazyLoading']) && !isset($arguments['loading'])) { + $this->addLazyLoading = true; + $this->lazyLoading = (string)$typoScriptSettings['lazyLoading']; + } } public function getPictureClass(): ?string diff --git a/Classes/ViewHelpers/ImageViewHelper.php b/Classes/ViewHelpers/ImageViewHelper.php index e02c4cd..6491672 100644 --- a/Classes/ViewHelpers/ImageViewHelper.php +++ b/Classes/ViewHelpers/ImageViewHelper.php @@ -181,7 +181,7 @@ public function render(): string $sourceOutputs[] = $tag->render(); // Build additional source with type webp if attribute addWebp is set and previously build tag is not type of webp already. - $type = $tag->getAttribute('type'); + $type = htmlspecialchars_decode($tag->getAttribute('type') ?? ''); if ($type !== 'image/webp' && $this->pictureConfiguration->webpShouldBeAdded()) { $tag = $this->addWebpImage($sourceConfiguration, $imageSrc); array_unshift($sourceOutputs, $tag->render()); @@ -214,7 +214,7 @@ protected function buildVariantsIfNeeded(array $configuration, FileInterface $im if (!empty($configuration['variants'])) { $processingInstructions = $this->getProcessingInstructions($configuration, $image); $ratio = null; - $variants = GeneralUtility::intExplode(',', $configuration['variants']); + $variants = GeneralUtility::intExplode(',', (string)$configuration['variants']); sort($variants); // determine the ratio if (!empty($configuration['width']) && !empty($configuration['height'])) { @@ -222,16 +222,18 @@ protected function buildVariantsIfNeeded(array $configuration, FileInterface $im $height = (int)preg_replace('/[^0-9]/', '', (string)$configuration['height']); $ratio = $width / $height; } + $useWidthHeight = $ratio !== null || empty($configuration['maxWidth']); + $useMaxWidth = !empty($configuration['maxWidth']); foreach ($variants as $variant) { // build processing instructions for each srcset variant $srcsetWidth = $variant; $srcsetHeight = ($ratio ? $variant * (1 / $ratio) : null); $srcsetProcessingInstructions = [ - 'width' => $srcsetWidth . (strpos((string)$configuration['width'], 'c') ? 'c' : ''), - 'height' => $srcsetHeight . (strpos((string)$configuration['height'], 'c') ? 'c' : ''), + 'width' => $useWidthHeight ? ($srcsetWidth . (strpos((string)$configuration['width'], 'c') ? 'c' : '')) : null, + 'height' => $useWidthHeight && $srcsetHeight ? ($srcsetHeight . (strpos((string)$configuration['height'], 'c') ? 'c' : '')) : null, 'minWidth' => null, 'minHeight' => null, - 'maxWidth' => null, + 'maxWidth' => $useMaxWidth ? $srcsetWidth : null, 'maxHeight' => null, 'crop' => $processingInstructions['crop'], ]; @@ -375,7 +377,7 @@ protected function addRetina(array $processingInstructions, TagBuilder $tag, Fil // Process additional retina images. Tag value can be gathered for source tags from srcset value as there it // was to be set already because adding retina is not mandatory. if ($tag->hasAttribute('srcset')) { - $tagValue = $tag->getAttribute('srcset'); + $tagValue = htmlspecialchars_decode($tag->getAttribute('srcset') ?? ''); $tag->removeAttribute('srcset'); } else { $tagValue = $imageUriRegular; @@ -422,11 +424,13 @@ protected function addWebpImage(array $configuration, FileInterface $image): Tag */ protected function wrapWithPictureElement(array $output): array { + $attributes = ''; if ($this->pictureConfiguration->hasPictureClass()) { - array_unshift($output, ''); - } else { - array_unshift($output, ''); + $attributes = ' ' . GeneralUtility::implodeAttributes([ + 'class' => $this->pictureConfiguration->getPictureClass(), + ]); } + array_unshift($output, ''); $output[] = ''; return $output; } diff --git a/README.md b/README.md index c49c350..e9af47b 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,9 @@ See `EXT:picture/Configuration/TypoScript/setup.typoscript` for possible configu ## Attributes ### All from f:image -Our image ViewHelper extends from the Fluid Image ViewHelper, so it has all the same attributes, including: +Our image ViewHelper mimics the Fluid Image ViewHelper, so it has all the same attributes, including: * `width` and `height`, including `c` option for crop scaling +* `maxWidth` for proportional scaling, without upscaling * `fileExtension` to set a file extension (to force webp for example) * `alt` and `title` * `cropVariant` diff --git a/Tests/Functional/Frontend/TagRenderingTest.php b/Tests/Functional/Frontend/TagRenderingTest.php index 8c770b3..b731567 100644 --- a/Tests/Functional/Frontend/TagRenderingTest.php +++ b/Tests/Functional/Frontend/TagRenderingTest.php @@ -222,7 +222,7 @@ public function imageWithPictureClassRenderPictureTag(): void $this->importCSVDataSet(__DIR__ . '/Fixtures/image_with_picture_class.csv'); $response = $this->executeFrontendSubRequest(new InternalRequest('http://localhost/')); $body = (string)$response->getBody(); - $expected = ''; + $expected = ''; self::assertStringContainsString($expected, $body); } diff --git a/Tests/Functional/ViewHelpers/Fixtures/ImageWithSourcesAndRetina.html b/Tests/Functional/ViewHelpers/Fixtures/ImageWithSourcesAndRetina.html new file mode 100644 index 0000000..0fc990e --- /dev/null +++ b/Tests/Functional/ViewHelpers/Fixtures/ImageWithSourcesAndRetina.html @@ -0,0 +1,9 @@ + + + diff --git a/Tests/Functional/ViewHelpers/ImageViewHelperTest.php b/Tests/Functional/ViewHelpers/ImageViewHelperTest.php index ffecaa4..79f0931 100644 --- a/Tests/Functional/ViewHelpers/ImageViewHelperTest.php +++ b/Tests/Functional/ViewHelpers/ImageViewHelperTest.php @@ -47,6 +47,26 @@ public function imageWithSources(): void self::assertTrue(str_contains(trim($content), 'setTemplatePathAndFilename($template); + $content = $view->render(); + $this->assertProcessedFileExists(150, 150); + $this->assertProcessedFileExists(300, 300); + $this->assertProcessedFileExists(1680, 1000); + $this->assertProcessedFileExists(3360, 2000); + self::assertTrue(str_starts_with(trim($content), '