# Extending Imager X

In addition to the built-in functionality, you can extend Imager to make it even more powerful. You can add your own effects, optimizers, external storages PRO, and even transformers PRO.

WARNING

Please note; contrary to what the craft documentation recommends (opens new window) the event listeners below should not be placed inside Craft::$app->onInit(), but rather directly in the init() function of your plugin/module.

# Effects

Custom effects can be added by listening for the EVENT_REGISTER_EFFECTS event:

Event::on(\spacecatninja\imagerx\ImagerX::class,
    \spacecatninja\imagerx\ImagerX::EVENT_REGISTER_EFFECTS,
    static function (\spacecatninja\imagerx\events\RegisterEffectsEvent $event) {
        $event->effects['myeffect'] = MyEffect::class;
    }
);

The registered class must implement the ImagerEffectsInterface (opens new window), and can then be used in your templates like this:

{% set transform = craft.imagerx.transformImage(image, { width: 800 }, { effects: { myeffect: [0.6, 'rgb(210,89,222)'] } }) %}

Have a look at the built-in effects (opens new window) for more examples of how effects can manipulate the image.

# Optimizers

Custom optimizers can be added by listening for the EVENT_REGISTER_OPTIMIZERS event:

Event::on(\spacecatninja\imagerx\ImagerX::class,
    \spacecatninja\imagerx\ImagerX::EVENT_REGISTER_OPTIMIZERS,
    static function (\spacecatninja\imagerx\events\RegisterOptimizersEvent $event) {
        $event->optimizers['myoptimizer'] = MyOptimizer::class;
    }
);

The registered class must implement the ImagerOptimizeInterface (opens new window), and can then be used in your config like this:

'optimizers' => ['myoptimizer'],
'optimizerConfig' => [
    'myoptimizer' => [
        'extensions' => ['jpg'],
        'path' => '/usr/local/bin/myoptimizer',
        'options' => '-t -n40',
    ],
],

Please note that you decide yourself which config parameters your optimizer needs, but you should always add an 'extensions' parameter as shown above.

Have a look at the built-in optimizers (opens new window) for more examples of what optimizers can do.

# External storages

Custom external storages can be added by listening for the EVENT_REGISTER_EXTERNAL_STORAGES event:

Event::on(\spacecatninja\imagerx\ImagerX::class,
    \spacecatninja\imagerx\ImagerX::EVENT_REGISTER_EXTERNAL_STORAGES,
    static function (\spacecatninja\imagerx\events\RegisterExternalStoragesEvent $event) {
        $event->storages['mystorage'] = MyExternalStorage::class;
    }
);

The registered class must implement the ImagerStorageInterface (opens new window), and can then be used in your config like this:

'storages' => ['mystorage'],
'storageConfig' => [
    'mystorage' => [
        'accessKey' => 'KJA5GH8FDD3FR9T',
        'secretAccessKey' => 'awIoJA76e3baHGD94DaeF6',
        'region' => 'eu-west-1',
        'bucket' => 'mytransforms',
    ],
],

Please note that you decide yourself which config parameters your external storage needs.

Have a look at the built-in storages (opens new window) for more examples of how external storages work.

# File adapters

Support for file adapters were added in Imager X 4.1

File adapters is a way to create transforms of files that would not usually be transformable as an image. It could be a PDF, video, or even an URL to a web page. It's up to the file adapter to do the heavy lifting, and provide imager with a path to an image that can be transformed.

The registered class must implement the ImagerAdapterInterface (opens new window),

The adapters constructor should take a file of some sort as its first parameter, and an optional array as it's second parameter.

You can either create an instance of your adapter, and pass that into Imager, or the adapter can register any number of file extensions that automatically should trigger the adapter to load.

To register your adapter, use the EVENT_REGISTER_ADAPTER event:

Event::on(\spacecatninja\imagerx\ImagerX::class,
    \spacecatninja\imagerx\ImagerX::EVENT_REGISTER_ADAPTERS,
    static function (\spacecatninja\imagerx\events\RegisterAdaptersEvent $event) {
        $event->adapters['pdf'] = PDF::class;
    }
);

You can now open files with the pdf extension automatically like this:

{% set transforms = craft.imagerx.transformImage(myPdfAsset, { width: 200 }) %}

TIP

If you've registered your adapter using the EVENT_REGISTER_ADAPTER event, adapters even works with the auto generate functionality! Just make sure you enable the necessary file extensions in the safeFileFormats config setting.

Creating an instance of the adapter first, lets you access any other helper methods and settings you'd need/want on your adapter:

{% set pdf = craft.pdfadapter.load(asset, { page: 1, density: 300 }) %}

Pages: {{ pdf.getNumPages() }}<br>

{% do pdf.setPage(5) %}

{% set transformPage5 = craft.imagerx.transformImage(pdf, { width: 600 }) %}

If you use the first methid, you can use the transform parameter adapterParams to pass settings to the adapter per transform:

{% set transforms = craft.imagerx.transformImage(myPdfAsset, { width: 200, adapterParams: { page: 5, density: 300 } }) %}

# Transformers

TIP

Transformers are the most complex thing you can extend Imager with, and is not for the faint hearted. 😮 If you still want to give it a go, make sure you have a look at the existing transformers and get an understanding of the overall flow.

Custom transformers can be added by listening for the EVENT_REGISTER_TRANSFORMERS event:

Event::on(\spacecatninja\imagerx\ImagerX::class,
    \spacecatninja\imagerx\ImagerX::EVENT_REGISTER_TRANSFORMERS,
    static function (\spacecatninja\imagerx\events\RegisterTransformersEvent $event) {
        $event->transformers['mytransformer'] = MyTransformer::class;
    }
);

The registered class must implement the TransformerInterface (opens new window), and can then be used in your config like this:

'transformer' => 'mytransformer',

The transformer should return a model representing the transformed image which implements TransformedImageInterface (opens new window). Some properties may not be applicable for all kinds of transformers, but the model should handle this gracefully (ie, return empty values that the template code can check for).