How to Add a New Transformation

Quick Overview

This cookbook is about a feature only provided in the Enterprise Edition.

Transformations are classes which allow to transform a file from state A to state B. For example, in the Product Asset specific case, they transform a file coming from a Reference (A) to a Variation file (B). Each Variation is a transformation of a Reference.

Php5-gd is used in Akeneo PIM but you can add you own library to transform your file. The supported file formats are jpg, png and gif.

As Transformations are not specific PIM elements, they are located in \Akeneo and not \PimEnterprise. Then, you can find in Akeneo\Component\FileTransformer all business code and in Akeneo\Bundle\FileTransformerBundle all Symfony2 specific implementation.

Transformation runs with the registry pattern. You have to create your own Transformation implementing Akeneo\Component\FileTransformer\Transformation\TransformationInterface and register the service with the akeneo_file_transformer.transformation tag. Then, compiler pass will inject your tagged Transformation in the registry which will make it available.

Note

Learn more about registry pattern.

This cookbook assumes that you already created a new bundle to add your new Transformation. Let’s assume its namespace is Acme\CustomBundle.

Create a New Transformation

For the need of the cookbook, we’ll add a watermark transformation.

Note

To learn more about this transformation you can read the ImageMagick watermark documentation.

In order to create your transformation, you have to follow these rules:

  • your transformation has to implement Akeneo\Component\FileTransformer\Transformation\TransformationInterface.
  • your transformation must have a unique name.
  • your transformation service must be tagged akeneo_file_transformer.transformation.
# /src/Acme/Bundle/CustomBundle/FileTransformer/Transformation/Image/Watermark.php
<?php

namespace Acme\CustomBundle\FileTransformer\Transformation\Image;

use Akeneo\Component\FileTransformer\Options\TransformationOptionsResolverInterface;
use Akeneo\Component\FileTransformer\Transformation\AbstractTransformation;

/**
 * Watermark transformation
 */
class Watermark extends AbstractTransformation
{
    /** @var ImageMagickLauncher */
    protected $launcher;

    /**
     * @param TransformationOptionsResolverInterface $optionsResolver
     * @param ImageMagickLauncher                    $launcher
     * @param array                                  $supportedMimeTypes
     */
    public function __construct(
        TransformationOptionsResolverInterface $optionsResolver,
        ImageMagickLauncher $launcher,
        array $supportedMimeTypes = ['image/jpeg', 'image/png']
    ) {
        $this->optionsResolver    = $optionsResolver;
        $this->supportedMimeTypes = $supportedMimeTypes;
        $this->launcher           = $launcher;
    }

    /**
     * $options = [
     *      'font'      => 'Arial'   by default
     *      'size'      => '12'      by default
     *      'watermark' => 'my mark' what you want to write in watermark
     * ];
     *
     * {@inheritdoc}
     */
    public function transform(\SplFileInfo $file, array $options = [])
    {
        $options  = $this->optionsResolver->resolve($options);

        $fontPart = '-font ' . $options['font'];
        $sizePart = '-pointsize ' . $options['size'];
        $blackWatermarkPart = 'fill black text ' . $options['position'] . ' \'' . $options['watermark'] . '\'';
        $whiteWatermarkPart = 'fill white text ' . $options['position'] . ' \'' . $options['watermark'] . '\'';
        $drawPart = '-draw "gravity south ' . $blackWatermarkPart . ' ' . $whiteWatermarkPart . '"';
        $cmd = $fontPart . ' ' . $sizePart . ' ' . $drawPart;

        $this->launcher->convert($cmd, $file->getPathname());
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'watermark';
    }
}

Note

To see how the imagemagick command is launched, you can take a look at the Akeneo\Component\FileTransformer\Transformation\Image\ImageMagickLauncher class.

In order to rely on options you can add an OptionsResolver, for this you need to follow this rule:

  • your OptionsResolver must implement the Akeneo\Component\FileTransformer\Options\TransformationOptionsResolverInterface.
#/src/Acme/Bundle/CustomBundle/FileTransformer/Options/Image/WatermarkOptionsResolver.php
<?php

namespace Acme\CustomBundle\FileTransformer\Options\Image;

use Akeneo\Component\FileTransformer\Exception\InvalidOptionsTransformationException;
use Akeneo\Component\FileTransformer\Options\TransformationOptionsResolverInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
 * Watermark Options Resolver
 */
class WatermarkOptionsResolver implements TransformationOptionsResolverInterface
{
    /** @var OptionsResolver */
    protected $resolver;

    public function __construct()
    {
        $this->resolver = new OptionsResolver();
        $this->resolver->setRequired([
            'font',
            'size',
            'watermark',
            'positionBlack',
            'positionWhite',
        ]);
        $this->resolver->setAllowedTypes([
            'font'          => 'string',
            'size'          => 'string',
            'watermark'     => 'string',
            'positionBlack' => 'string',
            'positionWhite' => 'string',
        ]);
        $this->resolver->setDefaults([
            'font'          => 'Arial',
            'size'          => '12',
            'watermark'     => 'Copyright',
            'positionBlack' => '0,45',
            'positionWhite' => '1,43',
        ]);
    }

    /**
     * {@inheritdoc}
     */
    public function resolve(array $options)
    {
        try {
            $options = $this->resolver->resolve($options);
        } catch (\Exception $e) {
            throw InvalidOptionsTransformationException::general($e, 'watermark');
        }

        return $options;
    }
}

Note

You can learn more about this Symfony2 component in the OptionsResolver documentation.

Next step is to create corresponding services in a dedicated file services.yml:

# src/Acme/Bundle/CustomBundle/FileTransformerBundle/Resources/config/services.yml
parameters:
    akeneo_file_transformer.options.image.watermark.class:        Acme\CustomBundle\FileTransformer\Options\Image\WatermarkOptionsResolver
    akeneo_file_transformer.transformation.image.watermark.class: Acme\CustomBundle\FileTransformer\Transformation\Image\Watermark

services:
    akeneo_file_transformer.options.image.watermark:
        class: '%akeneo_file_transformer.options.image.watermark.class%'

    akeneo_file_transformer.transformation.image.watermark:
        class: '%akeneo_file_transformer.transformation.image.watermark.class%'
        arguments:
            - '@akeneo_file_transformer.options.image.watermark'
            - '@akeneo_file_transformer.transformation.image.image_magick_launcher'
        tags:
            - { name: akeneo_file_transformer.transformation, alias: transformation_watermark }

Translate Asset Transformation Details for Channels

A translation key is automatically created with the Watermark->getName(). You can translate it in a dedicated translation file:

# src/Acme/Bundle/CustomBundle/Resources/translations/messages.en.yml

pimee_enrich.asset_transformation.watermark.title: Watermark
pimee_enrich.asset_transformation.watermark.options.size: Size
pimee_enrich.asset_transformation.watermark.options.watermark: Watermark
[...]
../../_images/cookbook_transformation_channel_configuration.png

Add a Channel Configuration to Use the New Transformation

Adding a channel configuration for Reference transformation is a simple YML import:

asset_channel_configurations:
     mobile:
          configuration:
              watermark:
                 size: 15
                 watermark: "Copyright Akeneo"

Once you created your YML file you can go to Akeneo PIM and then start importing with the asset channel configuration import in yml profile.

Be careful, if you import only the new channel configuration file, all your previous configurations will be removed. You need to add your old configuration(s) in the file to keep it.

Now try to create an asset and generate variations for your channel. Download the generated file and discover your watermark:

../../_images/logo_watermark.png