Giter Club home page Giter Club logo

picture's Introduction

CI

b13 Image View Helper

What it does

The b13 image view helper is a massive extension of the regular Fluid image ViewHelper. Basically it processes images and renders a single src element or a picture element depending on the specified configuration.

Installation

Install the extension using composer: composer req b13/picture.

Include the TypoScript within your main template:

@import 'EXT:picture/Configuration/TypoScript/setup.typoscript'

Use Fluid Namespace B13\Picture

Use a proper configured Fluid template adding the namespace when using this ViewHelper:

<html
  xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
  xmlns:i="http://typo3.org/ns/B13/Picture/ViewHelpers"
  data-namespace-typo3-fluid="true"
>

TypoScript setup

See EXT:picture/Configuration/TypoScript/setup.typoscript for possible configuration options (key: plugin.tx_picture):

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
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.
lazyLoading Use the loading attribute with images. See Browser Native Lazy Loading by Default
default: {$types.content.image.lazyLoading}

Attributes

All from f:image

Our image ViewHelper extends from the Fluid Image ViewHelper, so it has all the same attributes, including:

  • width and height, including c option for crop scaling
  • fileExtension to set a file extension (to force webp for example)
  • alt and title
  • cropVariant
  • loading to enable browser native lazy loading by default.

useRetina

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.

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 sources it adds an additional source tag above any source tag rendered by a given sources element.

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.

variants and sizes

Adds multiple variants of an image with different image sizes, optionally add a sizes-attribute to image tags:

variants="400, 600, 800, 1000" sizes="(min-width: 600px) 400px, 100vw"

This can also be part of the sources-Array (see below).

sources

Sources must be notated as array. For each element given a source tag is rendered. It accepts the same attributes as the fluid image view helper. The source tags are rendered in the same ordering as specified in the array. If you do not specify additional TypoScript settings, any key can be used.

sources="{
    0: {
        width: '300c', height: '300c', media: 'min-width: 1000px', cropVariant: 'desktop', variants: '400, 600, 800', sizes: '100vw'
    },
    1: {
        width: '250c', height: '250c', media: 'min-width: 600px', src: alternativefile.uid, treatIdAsReference: 1
    },
    2: {
        width: '200c', height: '200c', media: 'min-width: 300px', cropVariant: 'teaser'
    }
}"

pictureClass

Add a CSS class used for the picture element (if rendered using <picture>).

TypoScript Settings

In general

The following attributes can also be set in TypoScript as defaults for your whole site: addWebp, useRetina. A default setting can be overridden for each usage of the ViewHelper by setting the corresponding attribute.

retina

The retina option enables an extension of the default behaviour of the useRetina attribute. If retina is set, an array should be specified with the multiplier for the image size as key, and the multiplier value output in the corresponding tag.

retina {
    2 = 2x
    3 = 3x
}

breakpoints

With the array breakpoints you can use those settings by using keys in your Fluid template (instead of adding media queries for every key in your sources array). It simply adds a media query for min-width.

breakpoints {
    sm = 640
    md = 1024
    lg = 1280
}

Test rendering for demonstration purposes

You can include a test configuration to see the ViewHelper in your test instance frontend in action:

@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.

https://your.local.test.environment/?type=1573387706874

will render a page with different options to showcase code examples. This is intended for demonstration and testing purposes, not meant for your production environment.

Credits

This extension was created by Andreas Hämmerl and David Steeb in 2019 for b13 GmbH, Stuttgart.

Find more TYPO3 extensions we have developed 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.

picture's People

Contributors

achimfritz avatar bmack avatar brotkrueml avatar davidsteeb avatar georgringer avatar jschlier avatar o-ba avatar patta avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

picture's Issues

"src" attribute for breakpoint is ignored

If a different source image should be used for a breakpoint it is ignored (see use of swoosh-mobile/swoosh-desktop in this example):

Fluid:

<i:image src="EXT:my_template/Resources/Public/Assets/swoosh-mobile.png"
				 class="b_swoosh__image {f:if(condition: modifier, then: 'b_swoosh__image--{modifier}')}"
				 pictureClass="b_swoosh {f:if(condition: modifier, then: 'b_swoosh--{modifier}')}"
				 sources="{sm: {src: 'EXT:my_template/Resources/Public/Assets/swoosh-desktop.png'}}"
				 alt="Swoosh"
/>

HTML:

<picture class="b_swoosh ">
  <source media="(min-width: 768px)" srcset="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png, /typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png 2x" type="image/webp">
  <source media="(min-width: 768px)" srcset="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png, /typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png 2x">
  <source srcset="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png, /typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png 2x" type="image/webp">
  <img class="b_swoosh__image " alt="Swoosh" src="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png" width="1600" height="535" loading="lazy" srcset="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png, /typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png 2x">
</picture>

Variants are not taking "c" into account.

Looks like variant images are not taking into accounts crop in with and height.

<i:image src="{image.uid}"  
    treatIdAsReference="1"
    width="3840c"
    height="2160c"
   variants="960, 1920, 2560, 3840"
/>

The variants php code is:

foreach ($variants as $variant) {
      // build processing instructions for each srcset variant
      $srcsetWidth = $variant;
      $srcsetHeight = ($ratio ? $variant * (1/$ratio) : NULL);
      $srcsetProcessingInstructions = [
         'width' => $srcsetWidth,
         'height' => $srcsetHeight,
         'minWidth' => NULL,
         'minHeight' => NULL,
         'maxWidth' => NULL,
         'maxHeight' => NULL,
         'fileExtension' => $this->processingInstructions['fileExtension'],
         'crop' => $this->processingInstructions['crop']
       ];
      $srcsetImage = $this->applyProcessingInstructions($this->image, $srcsetProcessingInstructions);
      $srcsetValue .= ($srcsetValue ? ', ' : '');
      $srcsetValue .= $this->imageService->getImageUri($srcsetImage, $this->arguments['absolute']) . ' ' . $srcsetWidth . 'w';
 }

seems like possible solution could be just:

foreach ($variants as $variant) {
      // build processing instructions for each srcset variant
      $srcsetWidth = $variant;
      $srcsetHeight = ($ratio ? $variant * (1/$ratio) : NULL);
      $srcsetProcessingInstructions = [
         'width' => $srcsetWidth . (strpos($this->arguments['width'], 'c') ? 'c' : ''),
         'height' => $srcsetHeight . (strpos($this->arguments['height'], 'c') ? 'c' : ''),
         'minWidth' => NULL,
         'minHeight' => NULL,
         'maxWidth' => NULL,
         'maxHeight' => NULL,
         'fileExtension' => $this->processingInstructions['fileExtension'],
         'crop' => $this->processingInstructions['crop']
       ];
      $srcsetImage = $this->applyProcessingInstructions($this->image, $srcsetProcessingInstructions);
      $srcsetValue .= ($srcsetValue ? ', ' : '');
      $srcsetValue .= $this->imageService->getImageUri($srcsetImage, $this->arguments['absolute']) . ' ' . $srcsetWidth . 'w';
 }

Wrong cropping on 3x image

I am using the following snippet in my Fluid template:

<i:image image="{myImage}" width="720c" height="405c" alt=""/>

The original image has a dimension of 2638 x 1960 px.

A have the following TypoScript configuration:

plugin.tx_picture { useRetina = 1 retina { 2 = 2x 3 = 3x } }

So, the view helpers renders 1x, 2x and 3x:

<img alt="" src="/files/_/c/7/csm_623745_78347e7582.png" width="720" height="405" class="" loading="lazy" srcset="/files/_/c/7/csm_623745_78347e7582.png, /files/_/c/7/csm_623745_e00ad6418a.png 2x, /files/_/c/7/csm_623745_12388fa823.png 3x">

When I now check the sizes of the three scaled images, the dimension of the 3x image is not correct:

1x - 720 x 405
2x - 1440 x 810
3x - 2638 x 1960 - correct would be 2160 x 1215

Upload version 1.2.3 to TER

Hey there and thanks for your extension!
Would it be possible to upload the new 1.2.3 version to the TER?

Thanks in advance! :-)

Issue: TypeError in ImageViewHelper

Thanks for the good extension.

Versions:
TYPO3 v12.4.7 (composer mode)
PHP 8.2
Picture EXT: 2.0.3

Issue:
I got TypeError in ImageViewHelper when I used the "sources" attribute and set "variants" value.
explode(): Argument #2 ($string) must be of type string, int given at TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', 500)

Example:
<i:image image="{mediaElement}" addWebp="1" ....... sources="{ 0: {media: 'min-width: 1400px', cropVariant: 'default', variants: '700, 900', sizes: '100vw'}, 1: {media: 'min-width: 768px', cropVariant: 'medium', variants: '500', sizes: '100vw'}, 2: {media: 'min-width: 320px', cropVariant: 'small', variants: '400', sizes: '100vw'} }" />

So, I get TypeError whenvariants: '500' but for variants: '700, 900' it works fine.

The TypeError is caused because of the changes from https://forge.typo3.org/issues/97578

Solution:

On-Line https://github.com/b13/picture/blob/master/Classes/ViewHelpers/ImageViewHelper.php#L197
convert the value to a string using the (string)
$variants = GeneralUtility::intExplode(',', (string)$configuration['variants']);

additionalAttributes not correctly assigned

When using additionalAttributes on the image view helper, like:

<i:image image="{image}" additionalAttributes="{decoding: 'async'}"/>

The decoding attribute is assigned to the source tag instead to the img tag, what is obviously wrong.

I digged into the code: As the source tag is rendered first the additional attributes are assigned first to the source tag and seem to be gone for the img tag. Sadly, the additional attributes are already merged to the attributes property of the view helper. I think, one approach to solve this could be to separate the additional attributes again from the default attributes and assign them always to the img tag.

What do you think?

Retina and webp "versions" of SVG files

If retina and/or webp configuration is set globally, SVG files will be rendered as picture elements with additional (and wrong) "image/webp" versions and/or additional retina screen settings:

<picture>
  <source srcset="/fileadmin/test/extension-PermissionSets.svg, /fileadmin/test/extension-PermissionSets.svg 2x" type="image/webp">
  <img class="b_crosslink__image" alt="SVG Test" src="/fileadmin/test/extension-PermissionSets.svg" width="256" height="256" loading="lazy" srcset="/fileadmin/test/extension-PermissionSets.svg, /fileadmin/test/extension-PermissionSets.svg 2x">
</picture>

Wrong image type if no scaling/cropping of original image

If an image is used without any processing instruction to the source file, and webp option is activated, there's a second source-Tag supposed to be a webp image, but in fact is just the original png/jpg image, but with a wrong type attribute:

Fluid:

<i:image src="EXT:my_template/Resources/Public/Assets/swoosh-mobile.png"
				 class="b_swoosh__image {f:if(condition: modifier, then: 'b_swoosh__image--{modifier}')}"
				 pictureClass="b_swoosh {f:if(condition: modifier, then: 'b_swoosh--{modifier}')}"
				 sources="{sm: {src: 'EXT:my_template/Resources/Public/Assets/swoosh-desktop.png'}}"
				 alt="Swoosh"
/>

HTML:

<picture class="b_swoosh ">
  <source media="(min-width: 768px)" srcset="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png, /typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png 2x" type="image/webp">
  <source media="(min-width: 768px)" srcset="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png, /typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png 2x">
  <source srcset="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png, /typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png 2x" type="image/webp">
  <img class="b_swoosh__image " alt="Swoosh" src="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png" width="1600" height="535" loading="lazy" srcset="/typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png, /typo3conf/ext/my_template/Resources/Public/Assets/swoosh-mobile.png 2x">
</picture>

TypeError: preg_replace(): Argument #3 ($subject) must be of type array|string, float given

TYPO3 11.5.26
PHP 8.1.18
picture 2.0.2

(1/1) TypeError

preg_replace(): Argument #3 ($subject) must be of type array|string, float given

in /var/www/html/private/typo3conf/ext/picture/Classes/ViewHelpers/ImageViewHelper.php line 192

            $variants = GeneralUtility::intExplode(',', $configuration['variants']);
            sort($variants);
            // determine the ratio
            if (!empty($configuration['width']) && !empty($configuration['height'])) {
                $width = (int)preg_replace('/[^0-9]/', '', $configuration['width']);
                $height = (int)preg_replace('/[^0-9]/', '', $configuration['height']);
                $ratio = $width / $height;
            }
            foreach ($variants as $variant) {

at preg_replace('/[^0-9]/', '', 47.0)
in /var/www/html/private/typo3conf/ext/picture/Classes/ViewHelpers/ImageViewHelper.php line 192

            $variants = GeneralUtility::intExplode(',', $configuration['variants']);
            sort($variants);
            // determine the ratio
            if (!empty($configuration['width']) && !empty($configuration['height'])) {
                $width = (int)preg_replace('/[^0-9]/', '', $configuration['width']);
                $height = (int)preg_replace('/[^0-9]/', '', $configuration['height']);
                $ratio = $width / $height;
            }
            foreach ($variants as $variant) {

at B13\Picture\ViewHelpers\ImageViewHelper->buildVariantsIfNeeded(array('additionalAttributes' => array('draggable' => 'false'), 'data' => null, 'aria' => null, 'class' => null, 'dir' => null, 'id' => null, 'lang' => null, 'style' => null, 'title' => 'Folgen Sie uns LinkedIn', 'accesskey' => null, 'tabindex' => null, 'onclick' => null, 'alt' => null, 'ismap' => null, 'longdesc' => null, 'usemap' => null, 'loading' => null, 'decoding' => null, 'src' => '', 'treatIdAsReference' => false, 'image' => object(TYPO3\CMS\Core\Resource\FileReference), 'crop' => null, 'cropVariant' => 'default', 'fileExtension' => null, 'width' => 47.0, 'height' => 40.0, 'minWidth' => null, 'minHeight' => null, 'maxWidth' => null, 'maxHeight' => null, 'absolute' => false, 'useRetina' => null, 'addWebp' => null, 'lossless' => null, 'variants' => '380,520,680,800,1024,1200,1920', 'sizes' => '(min-width: 47px) 47px, 100vw', 'pictureClass' => null, 'sources' => null))
in /var/www/html/private/typo3conf/ext/picture/Classes/ViewHelpers/ImageViewHelper.php line 229

        $tag = clone $this->tag;
        $tag->setTagName($tagName);
        $tag = $this->removeForbiddenAttributes($tag);
        // generate a srcset containing a list of images if that is what we need
        $srcsetValue = $this->buildVariantsIfNeeded($configuration);
        $processingInstructions = $this->getProcessingInstructions($configuration);

        // generate a single image uri as the src
        // or

at B13\Picture\ViewHelpers\ImageViewHelper->buildSingleTag('img', array('additionalAttributes' => array('draggable' => 'false'), 'data' => null, 'aria' => null, 'class' => null, 'dir' => null, 'id' => null, 'lang' => null, 'style' => null, 'title' => 'Folgen Sie uns auf LinkedIn', 'accesskey' => null, 'tabindex' => null, 'onclick' => null, 'alt' => null, 'ismap' => null, 'longdesc' => null, 'usemap' => null, 'loading' => null, 'decoding' => null, 'src' => '', 'treatIdAsReference' => false, 'image' => object(TYPO3\CMS\Core\Resource\FileReference), 'crop' => null, 'cropVariant' => 'default', 'fileExtension' => null, 'width' => 47.0, 'height' => 40.0, 'minWidth' => null, 'minHeight' => null, 'maxWidth' => null, 'maxHeight' => null, 'absolute' => false, 'useRetina' => null, 'addWebp' => null, 'lossless' => null, 'variants' => '380,520,680,800,1024,1200,1920', 'sizes' => '(min-width: 47px) 47px, 100vw', 'pictureClass' => null, 'sources' => null))

n /var/www/html/private/typo3conf/ext/picture/Classes/ViewHelpers/ImageViewHelper.php line 138

        $settings = $this->getTypoScriptSettings();
        $this->pictureConfiguration = GeneralUtility::makeInstance(PictureConfiguration::class, $this->arguments, $settings, $this->image);

        // build the image tag
        $tag = $this->buildSingleTag('img', $this->arguments);
        $imageTag = $tag->render();

        // Add a webp source tag and activate nesting within a picture element only if no sources are set.
        if ($this->pictureConfiguration->webpShouldBeAddedBeforeSrcset()) {

at B13\Picture\ViewHelpers\ImageViewHelper->render()
at call_user_func(array(object(B13\Picture\ViewHelpers\ImageViewHelper), 'render'))
in /var/www/html/vendor/typo3fluid/fluid/src/Core/ViewHelper/AbstractViewHelper.php line 255

     */
    protected function callRenderMethod()
    {
        if (method_exists($this, 'render')) {
            return call_user_func([$this, 'render']);
        }
        if ((new \ReflectionMethod($this, 'renderStatic'))->getDeclaringClass()->getName() !== AbstractViewHelper::class) {
            // Method is safe to call - will not recurse through ViewHelperInvoker via the default
            // implementation of renderStatic() on this class.

...

cropvariants no longer working in srcset

since v2 the cropvariants in the srcset has no effect in the rendering.
This doesn't work any more

<i:image
  image="{images}"
  sources="{
    0: {width: '1450c', height: '551c', media: 'min-width: 760px', cropVariant: 'desktop'},
    1: {width: '760c', height: '370c', media: 'min-width: 450px', cropVariant: 'tablet'},
    2: {width: '440c', height: '450c', cropVariant: 'mobile'}
  }"
/>

Is this a wanted behaviour?

If not, the reason is in:

ImageViewHelper.php line 408:

        $cropVariant = $this->getCropVariant();

ImageViewHelper.php line 425

    protected function getCropVariant(): string
    {
        return $this->arguments['cropVariant'] ?: 'default';
    }

which returns everytime the select cropVariant of the baseimage.

Fallback src attribute for srcset is missing (IE11 Support)

If the variants attribute is set to render the srcset attribute, there is no fallback src attribute for the img tag.
Regardless whether the options addWebp or useRetina are enabled.

Without the src attribute, the image in never loaded in IE11. Which unfortunately is still a pre-installed web browser on windows and is actually still used.

Current srcset rendering:

<img 
width="400" height="200" 
title="" alt="" draggable="false"
srcset="https://mysite.site/small.jpg 320w, https://mysite.site/medium.jpg 640w, https://mysite.site/large.jpg 1024w" 
loading="lazy">

Recommended srcset rendering:

<img 
width="400" height="200" 
title="" alt="" draggable="false"
src="https://mysite.site/image.jpg" 
srcset="https://mysite.site/small.jpg 320w, https://mysite.site/medium.jpg 640w, https://mysite.site/large.jpg 1024w" 
loading="lazy">

It would be great if the src attribute could be integrated.

By the way, this extension is very helpful and should be implemented in the core ;)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.