From 513f9aa52bf7617fe2fa3fbcb29540a8cb5cf3e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20F=C3=B6rster?= Date: Fri, 10 Feb 2023 20:07:08 +0100 Subject: [PATCH 1/2] [FEATURE] Add AVIF image format @ --- Classes/Domain/Model/PictureConfiguration.php | 20 +++++++---- Classes/ViewHelpers/ImageViewHelper.php | 33 ++++++++++++++++++- Configuration/TypoScript/setup.typoscript | 15 +++++---- README.md | 20 +++++++---- 4 files changed, 68 insertions(+), 20 deletions(-) diff --git a/Classes/Domain/Model/PictureConfiguration.php b/Classes/Domain/Model/PictureConfiguration.php index c6daf3d..87b3c8a 100644 --- a/Classes/Domain/Model/PictureConfiguration.php +++ b/Classes/Domain/Model/PictureConfiguration.php @@ -17,8 +17,8 @@ class PictureConfiguration { protected bool $useRetina = false; - // 2x is default. Use multiple if retina is set in TypoScript settings. - protected array $retinaSettings = [2 => '2x']; + protected array $retinaSettings = [2 => '2x']; // 2x is default. Use multiple if retina is set in TypoScript settings. + protected bool $addAvif = false; protected bool $addWebp = false; protected bool $lossless = false; protected bool $addBreakpoints = false; @@ -34,11 +34,14 @@ public function __construct(array $arguments, array $typoScriptSettings, FileInt $this->arguments = $arguments; $fileExtension = $arguments['fileExtension'] ?? $image->getExtension(); if ($image->getExtension() !== 'svg') { - $this->addWebp = (bool)($fileExtension === 'webp' ? false : ($arguments['addWebp'] ?? $typoScriptSettings['addWebp'] ?? false)); $this->useRetina = (bool)($arguments['useRetina'] ?? $typoScriptSettings['useRetina'] ?? false); if (isset($typoScriptSettings['retina.'])) { $this->retinaSettings = $typoScriptSettings['retina.']; } + + $this->addAvif = (bool)($fileExtension === 'avif' ? false : ($arguments['addAvif'] ?? $typoScriptSettings['addAvif'] ?? false)); + $this->addWebp = (bool)($fileExtension === 'webp' ? false : ($arguments['addWebp'] ?? $typoScriptSettings['addWebp'] ?? false)); + $this->lossless = (bool)($arguments['lossless'] ?? $typoScriptSettings['lossless'] ?? false); if (isset($typoScriptSettings['breakpoints.'])) { $this->addBreakpoints = true; @@ -105,7 +108,7 @@ public function getRetinaSettings(): array public function pictureTagShouldBeAdded(): bool { - return $this->addWebp || $this->addSources; + return $this->addAvif || $this->addWebp || $this->addSources; } protected function breakPointsShouldBeAdded(): bool @@ -130,12 +133,17 @@ public function sourcesShouldBeAdded(): bool public function webpShouldBeAddedBeforeSrcset(): bool { - return $this->addWebp && !$this->addSources; + return $this->addWebp && !$this->addSources;// TODO : MOD ?? } public function webpShouldBeAddedAfterSrcset(): bool { - return $this->addWebp && $this->addSources; + return $this->addWebp && $this->addSources;// TODO : MOD ?? + } + + public function avifShouldBeAdded(): bool + { + return $this->addAvif; } public function webpShouldBeAdded(): bool diff --git a/Classes/ViewHelpers/ImageViewHelper.php b/Classes/ViewHelpers/ImageViewHelper.php index 9132279..6f8b15d 100644 --- a/Classes/ViewHelpers/ImageViewHelper.php +++ b/Classes/ViewHelpers/ImageViewHelper.php @@ -72,6 +72,12 @@ public function initializeArguments(): void 'Specifies if image should be displayed for retina as well.' ); + $this->registerArgument( + 'addAvif', + 'bool', + 'Specifies if a picture element with an additional avif image should be rendered.' + ); + $this->registerArgument( 'addWebp', 'bool', @@ -141,6 +147,7 @@ public function render(): string // Add a webp source tag and activate nesting within a picture element only if no sources are set. if ($this->pictureConfiguration->webpShouldBeAddedBeforeSrcset()) { $tag = $this->addWebpImage($this->arguments); + // TODO : ADD ?? $output[] = $tag->render(); } @@ -150,9 +157,14 @@ public function render(): string $sourceOutputs = []; $tag = $this->buildSingleTag('source', $sourceConfiguration); $sourceOutputs[] = $tag->render(); + $type = $tag->getAttribute('type'); + // Build additional source with type avif if attribute addAvif is set and previously build tag is not type of avif already. + if ($type !== 'image/avif' && $this->pictureConfiguration->avifShouldBeAdded()) { + $tag = $this->addAvifImage($sourceConfiguration); + array_unshift($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'); if ($type !== 'image/webp' && $this->pictureConfiguration->webpShouldBeAdded()) { $tag = $this->addWebpImage($sourceConfiguration); array_unshift($sourceOutputs, $tag->render()); @@ -165,6 +177,7 @@ public function render(): string // add a webp fallback for the default/non-sources image if addWebp is set if ($this->pictureConfiguration->webpShouldBeAddedAfterSrcset()) { $tag = $this->addWebpImage($this->arguments); + // TODO : ADD ?? $output[] = $tag->render(); } } @@ -377,6 +390,17 @@ protected function addRetina(array $processingInstructions, TagBuilder $tag): vo $tag->addAttribute('srcset', $tagValue); } + /** + * Function to add a avif element nested by a picture element. + */ + protected function addAvifImage(array $configuration): TagBuilder + { + $configuration['fileExtension'] = 'avif'; + $tag = $this->buildSingleTag('source', $configuration); + $tag->addAttribute('type', 'image/avif'); + return $tag; + } + /** * Function to add a webp element nested by a picture element. */ @@ -474,6 +498,13 @@ protected function getFrontendController(): ?TypoScriptFrontendController */ protected function applyProcessingInstructions(array $processingInstructions): ProcessedFile { + if (($processingInstructions['fileExtension'] ?? '') === 'avif' + && $this->image->getExtension() !== 'avif' + ) { + $jpegQuality = MathUtility::forceIntegerInRange($GLOBALS['TYPO3_CONF_VARS']['GFX']['jpg_quality'], 10, 100, 85); + $processingInstructions['additionalParameters'] = '-quality ' . $jpegQuality; + } + if (($processingInstructions['fileExtension'] ?? '') === 'webp' && $this->image->getExtension() !== 'webp' ) { diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index a41020e..329e6ac 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -1,13 +1,7 @@ plugin.tx_picture { - # Default for adding of images as webp. - addWebp = 0 - # Default for adding retina images. useRetina = 0 - # Default for using lossless compression for webp. - lossless = 0 - # Works only in combination with useRetina = 1. # The key must be the multiplier of the image size and the value the multiplier string added in the srcset # attribute's value. E.g. add "3 = 3x" to array: @@ -17,6 +11,15 @@ plugin.tx_picture { 2 = 2x } + # Default for adding of images as avif. + addAvif = 0 + + # Default for adding of images as webp. + addWebp = 0 + + # Default for using lossless compression for webp. + lossless = 0 + # Breakpoints for media query specified in the sources attribute: # breakpoints { # sm = 640 diff --git a/README.md b/README.md index afaf2f2..4d2c838 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ and renders a single src element or a picture element depending on the specified Install the extension using composer: `composer req b13/picture`. -Include the TypoScript within your main template: +Include the TypoScript within your main template: ``` @import 'EXT:picture/Configuration/TypoScript/setup.typoscript' @@ -34,8 +34,9 @@ See `EXT:picture/Configuration/TypoScript/setup.typoscript` for possible configu | TypoScript Configuration option | Description | |---------------------------------|-------------| -| addWebp | Add webp alternative image files as sources.
_default: 0_ | | useRetina | Add retina (2x) version of all images as sizes variants.
_default: 0_ | +| addAvif | Add avif alternative image files as sources.
_default: 0_ | +| addWebp | Add webp alternative image files as sources.
_default: 0_ | | lossless | Enable lossless compression for webp images.
_default: 0_ | | retina | Use custom or multiple multipliers for calculating retina image variants.
_default:
retina.2 = 2x
Only works in combination with `useRetina = 1` | | breakpoints | Use named breakpoints for easier markup of different image sizes for one picture element.
_default: empty_. | @@ -55,6 +56,11 @@ Our image ViewHelper extends from the Fluid Image ViewHelper, so it has all the If useRetina is set and not further specified in TypoScript setup, the corresponding `img` tag's or `source` tag’s attribute `srcset` is extended by a 2x retina version of the image. +### addAvif +Adds rendering of additional images in avif format. If it is specified without a given sources attribute, it renders a +picture tag instead of a single img tag in order to maintain a browser fallback. If it is specified together with +`sources` it adds an additional `source` tag above any `source` tag rendered by a given `sources` element. + ### addWebp Adds rendering of additional images in webp format. If it is specified without a given sources attribute, it renders a picture tag instead of a single img tag in order to maintain a browser fallback. If it is specified together with @@ -62,7 +68,7 @@ picture tag instead of a single img tag in order to maintain a browser fallback. ### lossless Enable lossless compression for webp images. If you find your webp images lacking in quality compared to jpg/png images, enable -this option to overwrite default settings for ImageMagick/GraphicsMagick. +this option to overwrite default settings for ImageMagick/GraphicsMagick. ### variants and sizes Adds multiple variants of an image with different image sizes, optionally add a sizes-attribute to image tags: @@ -96,7 +102,7 @@ Add a CSS class used for the `picture` element (if rendered using ``). ## TypoScript Settings ### In general -The following attributes can also be set in TypoScript as defaults for your whole site: `addWebp`, `useRetina`. +The following attributes can also be set in TypoScript as defaults for your whole site: `useRetina`, `addAvif`, `addWebp`. A default setting can be overridden for each usage of the ViewHelper by setting the corresponding attribute. ### retina @@ -128,8 +134,8 @@ You can include a test configuration to see the ViewHelper in your test instance `@import 'EXT:picture/Configuration/TypoScript/test.typoscript'` -This configuration enables frontend rendering of the test file with lots of different rendering examples using the -page type `1573387706874`. +This configuration enables frontend rendering of the test file with lots of different rendering examples using the +page type `1573387706874`. `https://your.local.test.environment/?type=1573387706874` @@ -142,4 +148,4 @@ This extension was created by Andreas Hämmerl and David Steeb in 2019 for b13 G [Find more TYPO3 extensions we have developed](https://b13.com/useful-typo3-extensions-from-b13-to-you) that help us deliver value in client projects. As part of the way we work, we focus on testing and best practices ensuring long-term -performance, reliability, and results in all our code. +performance, reliability, and results in all our code. From e665e48474eeb0166f247c408c4bffa01f719ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20F=C3=B6rster?= Date: Mon, 20 Feb 2023 09:09:12 +0100 Subject: [PATCH 2/2] [CLEANUP] Extension ICON --- Resources/Public/Icons/Extension.svg | 95 +++------------------------- 1 file changed, 9 insertions(+), 86 deletions(-) diff --git a/Resources/Public/Icons/Extension.svg b/Resources/Public/Icons/Extension.svg index 095a403..9f2af12 100644 --- a/Resources/Public/Icons/Extension.svg +++ b/Resources/Public/Icons/Extension.svg @@ -1,86 +1,9 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + \ No newline at end of file