Die TYPO3 ViewHelper sind ein mächtiges Werkzeug. Der Fluid-ViewHelper f:image bringt zahlreiche Funktionalitäten mit, um Bilder auszugeben. Aber leider kennt er keine GIFBUILDER-Effekte. Das können wir ändern.

GIFBUILDER

Eine der Funktionalitäten, mit denen TYPO3 schon sehr früh punkten konnte, war die Möglichkeit zur Bildmanipulation. Zum Glück muss man mittlerweile keine grafischen Menus mehr rendern; aber immer mal wieder sollen Wasserzeichen auf Bilder gerendert werden oder ein bestimmter Effekt angewendet werden. 

Der GIFBUILDER ist trotz seines antiquierten Namens nie aus dem TYPO3-Featureset verschwunden und nach wie vor Bestandteil von TypoScript. Anders als der Namen erwarten lässt, kann er auch wunderbar mit allen Arten von Bildern umgehen und arbeitet auch mit JPG und PNG-Dateien. 

Fluid-ViewHelper f:image

Der mit Fluid mitgelieferte ViewHelper f:image ist ein Standardwerkzeug in der Entwickler-Werkzeugkiste. Er kann Bilder in der passenden Größe rendern, unterstützt CropVarianten u.v.m. Aber mit dem GIFBUILDER kann er nicht umgehen. Das wollen wir ändern.

Ein eigener Image-ViewHelper

Zunächst erstellen wir dazu einen eigenen ViewHelper in unserem Sitepackage (oder der Extension, die wir verwenden wollen). Da wir das Rad nicht neu erfinden wollen, erben wir von der Standardklasse und machen nur Änderungen, wo es nötig ist.

 

<?php
namespace MarcWillmann\Sitepackage\ViewHelpers;

use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Imaging\GifBuilder;
use TYPO3\CMS\Core\Imaging\ImageManipulation\CropVariantCollection;
use TYPO3\CMS\Extbase\Exception;
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;

class ImageViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\ImageViewHelper
{


    /**
     * Initialize arguments.
     */
    public function initializeArguments()
    {
        parent::initializeArguments();
        $this->registerArgument('gifBuilderEffect', 'string', 'e.g. blur=20 | gamma=1.3', false, '');

    }
}

 

Hiermit registrieren wir ein weiteres Argument, mit dem im Template später der gewünschte Effekt übergeben werden kann. 

Die Methode render ist fast 1:1 von der originalen Datei übernommen

 

public function render()
    {
        if (($this->arguments['src'] === null && $this->arguments['image'] === null) || ($this->arguments['src'] !== null && $this->arguments['image'] !== null)) {
            throw new Exception('You must either specify a string src or a File object.', 1382284106);
        }

        try {
            $gifBuilderEffect = $this->arguments['gifBuilderEffect'];

            $image = $this->imageService->getImage($this->arguments['src'], $this->arguments['image'], $this->arguments['treatIdAsReference']);
            $cropString = $this->arguments['crop'];
            if ($cropString === null && $image->hasProperty('crop') && $image->getProperty('crop')) {
                $cropString = $image->getProperty('crop');
            }
            $cropVariantCollection = CropVariantCollection::create((string)$cropString);
            $cropVariant = $this->arguments['cropVariant'] ?: 'default';
            $cropArea = $cropVariantCollection->getCropArea($cropVariant);
            $processingInstructions = [
                'width' => $this->arguments['width'],
                'height' => $this->arguments['height'],
                'minWidth' => $this->arguments['minWidth'],
                'minHeight' => $this->arguments['minHeight'],
                'maxWidth' => $this->arguments['maxWidth'],
                'maxHeight' => $this->arguments['maxHeight'],
                'crop' => $cropArea->isEmpty() ? null : $cropArea->makeAbsoluteBasedOnFile($image),
            ];
            $processedImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);

            if ($gifBuilderEffect) {
                $conf = [
                    1 => 'IMAGE',
                    '1.' => [
                        'file' => $processedImage->getForLocalProcessing(false)
                    ],
                    20 => 'EFFECT',
                    '20.' => [
                        'value' => $gifBuilderEffect
                    ]
                ];
                $conf['XY'] = '[1.w],[1.h]';
                /** @var GifBuilder $gifCreator */
                $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
                $gifCreator->init();
                $gifCreator->start($conf, []);
                $imageUri = $gifCreator->gifBuild();
            }
            else {
                $imageUri = $this->imageService->getImageUri($processedImage, $this->arguments['absolute']);
            }

            if (!$this->tag->hasAttribute('data-focus-area')) {
                $focusArea = $cropVariantCollection->getFocusArea($cropVariant);
                if (!$focusArea->isEmpty()) {
                    $this->tag->addAttribute('data-focus-area', $focusArea->makeAbsoluteBasedOnFile($image));
                }
            }
            $this->tag->addAttribute('src', $imageUri);
            $this->tag->addAttribute('width', $processedImage->getProperty('width'));
            $this->tag->addAttribute('height', $processedImage->getProperty('height'));

            $alt = $image->getProperty('alternative');
            $title = $image->getProperty('title');

            // The alt-attribute is mandatory to have valid html-code, therefore add it even if it is empty
            if (empty($this->arguments['alt'])) {
                $this->tag->addAttribute('alt', $alt);
            }
            if (empty($this->arguments['title']) && $title) {
                $this->tag->addAttribute('title', $title);
            }
        } catch (ResourceDoesNotExistException $e) {
            // thrown if file does not exist
            throw new Exception($e->getMessage(), 1509741911, $e);
        } catch (\UnexpectedValueException $e) {
            // thrown if a file has been replaced with a folder
            throw new Exception($e->getMessage(), 1509741912, $e);
        } catch (\RuntimeException $e) {
            // RuntimeException thrown if a file is outside of a storage
            throw new Exception($e->getMessage(), 1509741913, $e);
        } catch (\InvalidArgumentException $e) {
            // thrown if file storage does not exist
            throw new Exception($e->getMessage(), 1509741914, $e);
        }

        return $this->tag->render();
    }

 

Der spannende Teil ist dieser hier, der besseren Übersicht aus dem o.g. Snippet nochmals herausgenommen:

 

[...]
$processedImage = $this->imageService->applyProcessingInstructions($image, $processingInstructions);

if ($gifBuilderEffect) {
    $conf = [
        1 => 'IMAGE',
        '1.' => [
            'file' => $processedImage->getForLocalProcessing(false)
        ],
        20 => 'EFFECT',
        '20.' => [
            'value' => $gifBuilderEffect
        ]
    ];
    $conf['XY'] = '[1.w],[1.h]';
    /** @var GifBuilder $gifCreator */
    $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
    $gifCreator->init();
    $gifCreator->start($conf, []);
    $imageUri = $gifCreator->gifBuild();
}
else {
    $imageUri = $this->imageService->getImageUri($processedImage, $this->arguments['absolute']);
}

 

Für den Fall, dass dem ViewHelper mit dem neu eingeführten Parameter eine GIFBUILDER-Anweisung übergeben wird, wenden wir diese nach an, nachdem die normalen Bild-Manipulationen abgeschlossen sind. 

Verwenden des neuen ViewHelpers

Diesen Image-ViewHelper können wir jetzt wie gewohnt in unserem Template verwenden. 

 

{namespace mw=MarcWillmann\Sitepackage\ViewHelpers}

[...]
<mw:image 
  image="{file}" 
  alt="{file.alternative}" 
  title="{file.title}"
  cropVariant="default" 
  width="1200"
  gifBuilderEffect="blur=50 | gray" 
/>

 

Damit haben wir alles beisammen, was wir benötigen. Das Ergebnis kann dann z.B. so aussehen:

Mit dem f:uri.image-ViewHelper ist dies natürlich analog genauso möglich. Ebenso könnte man statt (oder zusätzlich) zu den GIFBUILDER-Effekten auch mit dem GIFBUILDER-Text-Objekt einen Text auf das Bild rendern lassen o.ä.

Dokumentation

Eine Übersicht über alle zur Verfügung stehenden Effekte finden wir in der Dokumentation (TSRef) https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/Gifbuilder/ObjectNames/Index.html#effect

 

Kommentare (0)

Keine Kommentare gefunden!

Neuen Kommentar schreiben