Neos Media 4.3 Documentation

Neos Media package is a helper package to work with Assets in application based on Flow Framework or Neos CMS.

Neos Media package is licensed under the GPL.

This version of the documentation covering Neos Media 4.3.x has been rendered at: Nov 08, 2021

Variant Presets

Introduction

Neos Media provides a way to automatically generate variants of an original, based on configuration. This allows for creating images with different aspect ratios, or other adjustments, without further action of an editor.

For example, you may want to generate a square and a wide variant of a given original image in order to use them on your website. Using Fusion, you can access a specific variant generated through a preset, by referring to the preset’s identifier and the variant name.

This feature is currently in beta, therefore the API and functionality may change in a future release. It is mainly intended to be combined with further mechanisms, such as automatic image analysis which can set the optimal clipping for an image crop adjustment.

Variants vs. Thumbnails

The concept of variants and thumbnails are quite similar, but suit different purposes. It’s important to know which concept to choose for a specific use case, therefore let’s take a quick look at the differences:

An asset, or more specifically, an image, is either imported, uploaded or created. This is what we also call the “original asset”. The binary data of this asset is exactly the same which was imported in the first place and it never changes.

An original asset can have any number of variants. Variants are, as the name suggests, variants of an original which can have one or multiple adjustments applied. For example, there may be a variant which only shows a part of the image (by using a “crop adjustment”) or one which is a black and white version of the original (using a “grayscale adjustment”). These variants are persistent and can be used like an original asset. The main difference to an original is that

  1. they can be modified

  2. they are automatically deleted when the original is deleted

Finally, thumbnails are automatically generated previews of an original asset or a variant. They are used to make the representation of an asset more suitable for a specific case, for example by resizing an image to a specific size instead of using the original. Thumbnails are ephemeral, which means that they are created and destroyed automatically, and not manually by an editor.

Based on these concepts, you should use image variant presets, if you want to automate a task which would usually been carried out by an editor.

Configuration

Variant presets are defined in a Settings.yaml of a given package or distribution. Each preset defines one or more variants to be generated. Each variant can have one or more adjustments automatically applied.

For each preset, one or more media type patterns must be defined. These patterns are regular expressions which are use to match against the concrete IANA media type of a given asset. The configured variants are only created when at least one of the media type patterns matches. Note that you need to specify a complete regular expression, including delimiters (“~” in the example below).

The following example shows the required structure and possible fields of the presets configuration:

Neos:
  Media:
    variantPresets:
      'Flownative.Demo:Preset1':
        label: 'Demo Preset 1'
        mediaTypePatterns: ['~image/(jpe?g|png)~', '~image/vnd\.adobe\.photoshop~']
        variants:
          'wide':
            label: 'Wide'
            description: 'An optional description'
            icon: ''
            adjustments:
              crop:
                type: 'Neos\Media\Domain\Model\Adjustment\CropImageAdjustment'
                options:
                  aspectRatio: '16:9'
          'portrait':
            label: 'Portrait'
            description: ''
            icon: ''
            adjustments:
              crop:
                type: 'Neos\Media\Domain\Model\Adjustment\CropImageAdjustment'
                options:
                  aspectRatio: '3:4'
          'square':
            label: 'Square'
            description: ''
            icon: ''
            adjustments:
              crop:
                type: 'Neos\Media\Domain\Model\Adjustment\CropImageAdjustment'
                options:
                  aspectRatio: '1:1'

The automatic variant generation for new assets has to be enabled via setting as by default this feature is disabled.

Neos:
  Media:
    autoCreateImageVariantPresets: true

To show and edit the variants in the media module the variants tab has to be enabled.

Neos:
  Media:
    Browser:
      features:
        variantsTab:
          enable: true

Thumbnail Presets

Introduction

Thumbnail presets allows thumbnails to be easily reused to reduce the amount of rendered thumbnails.

Configuration

Thumbnails presets are configured using configuration settings in Neos.Media.thumbnailPresets. It accepts the parameters used in ThumbnailConfiguration, except for the async parameter.

TYPO3:
  Media:
    thumbnailPresets:
      'Acme.Demo:Thumbnail':
        maximumWidth: 500
        maximumHeight: 500

Optimization

When new assets are uploaded, thumbnails for the configured presets are automatically created, unless disabled using the configuration setting Neos.Media.autoCreateThumbnailPresets.

If Asynchronous Thumbnail Generation is disabled, the thumbnails will be rendered immediately making uploading slower.

Utilities

To create or clear thumbnails for configured presets use the typo3.media:media:createthumbnails and typo3.media:media:clearthumbnails commands, see Media Command Reference.

Asynchronous Thumbnail Generation

Introduction

To optimize response times, generation of thumbnails can be done asynchronously. Usage of asynchronous thumbnail generation is determined in the image view helpers usage with the async flag. When the flag is used, a link to the thumbnail controller returned instead of rendering the thumbnail if the thumbnail hasn’t already been rendered. The thumbnail controller takes a thumbnail object, renders it, if not already done, and redirects to the thumbnail file.

Usage

To use asynchronous thumbnail generation set the async parameter to TRUE in the image view helpers, see Media ViewHelper Reference.

Configuration

The configuration setting Neos.Media.asyncThumbnails is used to determine if asynchronous thumbnails are rendered when creating thumbnails for configured Thumbnails Presets.

The setting is additionally used as the default value for the media:createthumbnails command, see Media Command Reference.

Optimization

Since several simultaneous requests for thumbnails can occur, depending on browser and concurrent users, busy servers can experience performance issues. Therefore it is recommended to configure the server to run the command media:renderthumbnails often or use a job queue by listening to the thumbnailCreated signal and calling refreshThumbnail for the thumbnail in the thumbnail service.

Tip

Configure crontab to run the render command every minute: * * * * * /path/to/site/flow media:renderthumbnails

Use media:clearthumbnails and media:createthumbnails to refresh thumbnails.

Thumbnail Generator

Introduction

Thumbnail Generators allows previewing different kinds of assets by generating thumbnails for them.

Available Generators

The Neos Media package contains the following generators:

  • Document Thumbnail Generator (DocumentThumbnailGenerator)

    Generates a Thumbnail for any document type supported by Imagick. By default enabled for PDF, EPS and AI (Illustrator).

  • Font Thumbnail Generator (FontThumbnailGenerator)

    Generates a Thumbnail for any font type supported by GD. By default enabled for TTF and ODF.

  • Icon Thumbnail Generator (IconThumbnailGenerator)

    Returns a static icon image from common types of Assets, based on the asset MIME type.

  • Image Thumbnail Generator (ImageThumbnailGenerator)

    Generates a Thumbnail for any image types supported by GD, Imagick or Gmagick.

Configuration

How to configure Generator Priority

In some cases, you need to replace the current Generator by your own implementation or for exemple to replace the PDF Thumbnail Generator by the Icon Generator for a specific project.

You can do that by configuring each Generator priority.

Change the priority of an existing Generator

You can change the priority (higher is better) for an existing Generator, by editing you Settings.yaml:

Neos:
  Media:
    thumbnailGenerators:
      'Neos\Media\Domain\Model\ThumbnailGenerator\DocumentThumbnailGenerator':
        priority: 100
Disabling an existing Generator

To disable an existing Generator use the disable configuration option for the desired Generator:

Neos:
  Media:
    thumbnailGenerators:
      'Neos\Media\Domain\Model\ThumbnailGenerator\IconThumbnailGenerator':
        disable: true

Specific configuration

Check Settings.yaml in the Media package to see the available configurations by Generator:

'Neos\Media\Domain\Model\ThumbnailGenerator\DocumentThumbnailGenerator':
    resolution: 120
    supportedExtensions: [ 'pdf', 'eps', 'ai' ]
    paginableDocuments: [ 'pdf' ]

Build your own Generator

Implement your own generator

To implement your own Generator, first check the code of the Generators included in the Media package.

Basically, you need to extend AbstractThumbnailGenerator and implement the ThumbnailGeneratorInterface::refresh() method. The refresh method receives a Thumbnail object, based on this object do the required processing to generate a thumbnail. In most cases the Thumbnail can be persisted by attaching the new resource to the Thumbnail object.

Determine if a Generator can handle the current Thumbnail

You can also implement the ThumbnailGeneratorInterface::canRefresh() if your Generator has some specific requirements (like maximum file size, MIME type, external service availability, etc.).

Priority

The ThumbnailGeneratorStrategy choose the Generator by two factors, the value of the static property priority and the return value of the method ThumbnailGeneratorInterface::canRefresh(). For priority value, higher is better:

class YourOwnThumbnailGenerator extends AbstractThumbnailGenerator
{
    /**
     * @var integer
     * @api
     */
    protected static $priority = 100;
}

You can always override this priority in your Settings.yaml.

Configuration

In your generator class use the AbstractThumbnailGenerator::getOption() to access your settings:

Neos:
  Media:
    thumbnailGenerators:
      'Your\Package\Domain\Model\ThumbnailGenerator\YourOwnThumbnailGenerator':
        priority: 100
        parameterOne: 100
        parameterTwo: 200

Remember to add the Media Package in your package composer.json` to load the Media package before your own:

{
    ...
    "require": {
        "neos/flow": "*",
        "neos/media": "*"
    }
    ...
}

Community supported Generators

  • FilePreviews

    Can be use to integrate the service from filepreviews.io in your project and generate thumbnail for Office or Audio documents.

Feel free to contact us at hello@neos.io, if you publish some Generators under an open-source licence.

Configure image generation

Changing output quality of images

You can change the output quality of generated images within your Settings.yaml. Set the quality to your preferred value (between 0 - very poor and 100 - very good).

Neos:
  Media:
    image:
      defaultOptions:
        'quality': 90

Convert CMYK images into RGB

If you are working with CMYK images and don’t like to convert them automatically into RGB for any reason, you can deactivate this within your Settings.yaml:

Neos:
  Media:
    image:
      defaultOptions:
        convertCMYKToRGB: false #default is true

Changed default filter for Image processing

If you have configured a Imagine driver that support alternative filter (this the case is you use Imagick or Gmagick), you can select the filter within your Settings.yaml:

Neos:
  Media:
    image:
      defaultOptions:
        resizeFilter: '%\Imagine\Image\ImageInterface::FILTER_UNDEFINED%'

Unfortunatly Gd does not support other filter than the default one. Good candidate can be FILTER_BOX or FILTER_CATROOM. You can check the documentation of your image driver for more informations about each filter. Check the ImagineImageImageInterface to know with filter are supported by Imagine.

Produce interlaced images

To generate progressive images you can configure the driver within your Settings.yaml:

   Neos:
     Media:
       image:
         defaultOptions:
           interlace: '%\Imagine\Image\ImageInterface::INTERLACE_LINE%'

Check the \Imagine\Image\ImageInterface to know with mode are supported by Imagine.

Asset Privileges

Introduction

Asset privileges allows assets to be restricted based on authenticated roles. This package comes with the following privileges:

Restrict read access to Assets based on their media type

privilegeTargets:
  'Neos\Media\Security\Authorization\Privilege\ReadAssetPrivilege':
    'Some.Package:ReadAllPDFs':
      matcher: 'hasMediaType("application/pdf")'

Restrict read access to Assets based on Tag

privilegeTargets:
  'Neos\Media\Security\Authorization\Privilege\ReadAssetPrivilege':
    'Some.Package:ReadConfidentialAssets':
      matcher: 'isTagged("confidential")'

Restrict read access to Assets based on Asset Collection

privilegeTargets:
  'Neos\Media\Security\Authorization\Privilege\ReadAssetPrivilege':
    'Some.Package:ReadSpecialAssets':
      matcher: 'isInCollection("some-collection")'

Of course you can combine the three matchers like:

privilegeTargets:
  'Neos\Media\Security\Authorization\Privilege\ReadAssetPrivilege':
    'Some.Package:ReadConfidentialPdfs':
      matcher: 'hasMediaType("application/pdf") && isTagged("confidential")'

Restrict read access to Tags based on Tag label or id

You can match on the label of a Tag:

privilegeTargets:
  'Neos\Media\Security\Authorization\Privilege\ReadTagPrivilege':
    'Some.Package:ReadConfidentialTags':
      matcher: 'isLabeled("confidential")'

Or on its technical identifier (UUID):

privilegeTargets:
  'Neos\Media\Security\Authorization\Privilege\ReadTagPrivilege':
    'Some.Package:ReadConfidentialTags':
      matcher: 'hasId("3e8300a6-e5a7-4c3f-aae6-4d7ce35f2caa")'

Restrict read access to Asset Collections based on Collection title or id

You can match on the title of an Asset Collection:

privilegeTargets:
  'Neos\Media\Security\Authorization\Privilege\ReadAssetCollectionPrivilege':
    'Some.Package:ReadSpecialAssetCollection':
      matcher: 'isTitled("some-collection")'

Or on its technical identifier (UUID):

privilegeTargets:
  'Neos\Media\Security\Authorization\Privilege\ReadAssetCollectionPrivilege':
    'Some.Package:ReadSpecialAssetCollection':
      matcher: 'hasId("7c1e8cbc-9205-406d-a384-f8e9440531ad")'

Complete Example:

Given you have three “groups” and corresponding roles Some.Package:Group1Editor, Some.Package:Group2Editor and Some.Package:Group3Editor as well as an administrative role ``Some.Package:Administrator`.

Now, if you have three “Asset Collections” named group1, group2 and group3 the following Policy.yaml would restrict editors to only see collections and assets corresponding to their role:

privilegeTargets:

  'Neos\Media\Security\Authorization\Privilege\ReadAssetPrivilege':

    'Some.Package:Group1.ReadAssets':
      matcher: 'isInCollection("group1")'
    'Some.Package:Group2.ReadAssets':
      matcher: 'isInCollection("group2")'
    'Some.Package:Group3.ReadAssets':
      matcher: 'isInCollection("group3")'

  'Neos\Media\Security\Authorization\Privilege\ReadAssetCollectionPrivilege':

    'Some.Package:Group1.ReadCollections':
      matcher: 'isTitled("group1")'
    'Some.Package:Group2.ReadCollections':
      matcher: 'isTitled("group2")'
    'Some.Package:Group3.ReadCollections':
      matcher: 'isTitled("group3")'

roles:

  'Your.Package:Administrator':
    privileges:
      -
        privilegeTarget: 'Some.Package:Group1.ReadAssets'
        permission: GRANT
      -
        privilegeTarget: 'Some.Package:Group1.ReadCollections'
        permission: GRANT
      -
        privilegeTarget: 'Some.Package:Group2.ReadAssets'
        permission: GRANT
      -
        privilegeTarget: 'Some.Package:Group2.ReadCollections'
        permission: GRANT
      -
        privilegeTarget: 'Some.Package:Group3.ReadAssets'
        permission: GRANT
      -
        privilegeTarget: 'Some.Package:Group3.ReadCollections'
        permission: GRANT

  'Your.Package:Group1Editor':
    privileges:
      -
        privilegeTarget: 'Some.Package:Group1.ReadAssets'
        permission: GRANT
      -
        privilegeTarget: 'Some.Package:Group1.ReadCollections'
        permission: GRANT

  'Your.Package:Group2Editor':
    privileges:
      -
        privilegeTarget: 'Some.Package:Group2.ReadAssets'
        permission: GRANT
      -
        privilegeTarget: 'Some.Package:Group2.ReadCollections'
        permission: GRANT

  'Your.Package:Group3Editor':
    privileges:
      -
        privilegeTarget: 'Some.Package:Group3.ReadAssets'
        permission: GRANT
      -
        privilegeTarget: 'Some.Package:Group3.ReadCollections'
        permission: GRANT

Developer Information

Asset Usage Strategies

It is possible to extend the media handling by defining asset usage strategies. Those strategies can tell the media package if an asset is in used, how many times it is used and how it is used.

An asset usage strategy is already implemented for Neos ContentRepository nodes under the sites root, like document and content nodes. For all other usage scenarios, you need to build your own strategy.

To define your own custom usage strategy you have to implement the Neos\Media\Domain\Strategy\AssetUsageStrategyInterface. For convenience you can extend the Neos\Media\Domain\Strategy\AbstractAssetUsageStrategy.

Example Strategy

use TYPO3\Flow\Annotations as Flow;
use Neos\Media\Domain\Strategy\AbstractAssetUsageStrategy;
use TYPO3\Flow\Persistence\PersistenceManagerInterface;

/**
 * @Flow\Scope("singleton")
 */
class MyCustomAssetUsageStrategy extends AbstractAssetUsageStrategy
{
    /**
     * @Flow\Inject
     * @var PersistenceManagerInterface
     */
    protected $persistenceManager;

    /**
     * @var array
     */
    protected $firstlevelCache = [];

    /**
     * Returns an array of usage reference objects.
     *
     * @param AssetInterface $asset
     * @return array<\Neos\Media\Domain\Model\Dto\UsageReference>
     */
    public function getUsageReferences(AssetInterface $asset)
    {
        $assetIdentifier = $this->persistenceManager->getIdentifierByObject($asset);
        if (isset($this->firstlevelCache[$assetIdentifier])) {
            return $this->firstlevelCache[$assetIdentifier];
        }

        // Your code to find asset usage
        foreach ($usages as $usage) {
            $this->firstlevelCache[$assetIdentifier] = new \Neos\Media\Domain\Model\Dto\UsageReference($asset);
        }

        return $this->firstlevelCache[$assetIdentifier];
    }
}

Extend Asset Validation

Imagine you need to extend the validation of assets. For example to prevent duplicate file names or to run copyright checks on images. You can do so by creating your own custom validator. If you make sure that your validator implements the \Neos\Media\Domain\Validator\AssetValidatorInterface it will be loaded on object validation. The added errors in your validator will be merged into the model validator of assets.

Example validator

<?php
namespace My\Package;

use TYPO3\Flow\Validation\Valwidator\AbstractValidator;
use Neos\Media\Domain\Model\AssetInterface;
use Neos\Media\Domain\Validator\AssetValidatorInterface;

class CustomValidator extends AbstractValidator implements AssetValidatorInterface
{

    /**
     * Check if $value is valid. If it is not valid, needs to add an error
     * to the result.
     *
     * @param AssetInterface $value
     * @return void
     */
    protected function isValid($value)
    {
        // Your object validation
        if ($errors) {
            $this->addError('Some error', 0123456789);
        }
    }
}