
Drupal 8/9 Image Effects
Problem / Motivation:
The problem I wanted to solve was - to apply image styles (especially with the Image Effects module), on images, but dynamically & on-demand, and not use dozens of pre-configured Image Styles.
Why would anyone want something like this? I can give you a couple of examples:
- Facebook / Twitter Preview image, for every post. Let’s say you want Drupal to generate an image, by using Post Cover, Post Date, Title and potentially slap on some tags - and compile a Facebook compatible final image.
- Gift Card Generator 🎴 - where users have a set of pre-configured options they may choose, colors, fonts, texts and use some pre-defined layouts to put everything together.
- Dynamic Watermarks 🖼 - allow users to upload their own watermarks and apply those on top of their images - without creating a custom Image Style per user.
- Banners - allow users to choose predefined layouts and craft their own banners.
- Automate SMM - if you have some content that once created should automatically post a Social Media article with an image - you can use this approach as well.
- Customization of Avatars 🗿 - similar way Facebook does - you can stitch them with text, images, canvases, etc.
- NFTs! Yeah, you could define traits and use Drupal to assemble vast collections, by programmatically overlaying the traits.
- Many other ideas, that I’m not currently aware of 😀
There are many ways one might want to achieve these:
- [low level] - Use PHP’s GD or ImageMagick library - here’s the full reference.
- [mid level] - use an implementation of GDImageToolkitOperationBase (which extends ImageToolkitOperation). The implementations of this class define an execute method that handles the transformation.
- [high level] - use an implementation of ConfigurableImageEffectBase (which extends ImageEffectBase). The implementations of these plugins have an applyEffect method.
Me being lazy, I didn’t want to use neither low level nor mid-level implementations. I wanted to use something that an Image Style would use - higher level. I know some devs like to have more control and would pick a lower level approach, but that’s not me (one of the reasons why I use Drupal in 1st place).
The fun part is that “high level”, I mean, using ConfigurableImageEffectBase - means using plugins - now let’s do a quick recap on Plugins and Plugin Managers.
About Plugins & Plugin Managers:
I’m definitely not the best person to explain what Plugins and Plugin Managers in Drupal are - but here’s an excellent explainer and video 🎥 from Joe Shindelar, on Drupalize.me.
Here’s also a full write-up on api.drupal.org & official docs.
“Plugins are small pieces of functionality that are swappable. Plugins that perform similar functionality are of the same plugin type.”
Drupal uses Plugins & Plugin Managers to create little reusable bits of code, think: Blocks, Entities, Search, etc - and yes, Image Effects (that are used in the Image Styles).
Image Effects - are plugins too:
Yep, Image Effects are plugins tpp, and they have a Plugin Manager as well, that manages them. Here’s an example of all the classes that implement ConfigurableImageEffectBase.

We can use all of these. But you can’t just make a new instance of the class and work with it - you have to use a Plugin Manager as a proxy for that. Assuming you’re using a dependency injection (in a service, controller or a custom form):
use Drupal\image\ImageEffectManager; // [...] /** * Image effect manager - used to fetch image effects. * * @var \Drupal\Core\Image\ImageEffectManager */ protected $imageEffectManager; /** * The overridden default constructor. */ public function __construct(ImageEffectManager $image_effect_manager) { $this->imageEffectManager = $image_effect_manager; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('plugin.manager.image.effect'), ); }
Once you have your plugin manager (instance of ImageEffectManager), you can request your plugins this way, and apply the effects on a given image:
// Set the options for a given effect. $extend_image_options = [ 'data' => [] ]; /** @var \Drupal\image_effects\Plugin\ImageEffect\SetCanvasImageEffect $extend_image */ $extend_image = $this->imageEffectManager->createInstance('image_effects_set_canvas', $extend_image_options); if (!$extend_image->applyEffect($image)) { \Drupal::messenger()->addError('Could not apply the effect - something went wrong'); }
Using Image Effects & Textimage, programmatically & dynamically:
Now, let’s see this in practice - let’s apply some Image Effects & Textimage effects. Let’s install and enable Image Effects first.
Then, we can use something like this:
$extend_image_options = [ 'data' => [ 'canvas_size' => 'exact', 'canvas_color' => '#000000', 'exact' => [ 'width' => '800', 'height' => '600', 'placement' => 'top-left', 'x_offset' => 0, 'y_offset' => 0, ], ] ]; /** @var \Drupal\image_effects\Plugin\ImageEffect\SetCanvasImageEffect $extend_image */ $extend_image = $this->imageEffectManager->createInstance('image_effects_set_canvas', $extend_image_options); if (!$extend_image->applyEffect($image)) { \Drupal::messenger()->addError('Could not apply the effect - something went wrong'); }
This will create a rectangle image 800x600 with a given canvas color. All of these are values so we can set these dynamically.
Now let’s play with text overlays - we need to install and enable the Textimage module. The $data variable for these effects are a bit bigger.
// Set these dynamically, via a form-submit or some other method. $details = [ 'font_uri' => $fonts_path . '/OpenSans.woff', 'font_size' => '80', 'color' => '#ff0000', 'x' => '50', 'y' => '100' ]; // Then you can use these below. $text_overlay_options = [ 'data' => [ 'font' => [ 'name' => 'OpenSans', 'uri' => $details['font_uri'], 'size' => $details['font_size'], 'angle' => 0, 'color' => $details['color'], 'stroke_mode' => FALSE, 'stroke_color' => '#000000FF', 'outline_top' => 0, 'outline_right' => 0, 'outline_bottom' => 0, 'outline_left' => 0, 'shadow_x_offset' => 1, 'shadow_y_offset' => 1, 'shadow_width' => 0, 'shadow_height' => 0, ], 'layout' => [ 'padding_top' => 0, 'padding_right' => 20, 'padding_bottom' => 0, 'padding_left' => 0, 'x_offset' => 0, 'y_offset' => 0, 'background_color' => NULL, 'overflow_action' => 'extend', 'extended_color' => NULL, 'x_pos' => $details['x'], 'y_pos' => $details['y'], ], 'text_string' => $string, ] ]; /** @var \Drupal\image_effects\Plugin\ImageEffect\TextOverlayImageEffect $text_overlay */ $text_overlay = $this->imageEffectManager->createInstance('image_effects_text_overlay', $text_overlay_options); $text_overlay->applyEffect($image);
You can surely make more changes and adopt these to your own needs 🙃 these are just some random examples.
Putting it all together: a tiny demo module:
Okay this definitely took some time - but I’ve finally finished working on a demo module. If you want to see this in action - just head to - https://github.com/Nikro/blog-drupal-demos
Make sure you have docksal (and hence - docker) installed, and then just clone and run: fin init

You will be able to navigate to: /admin/config/demo/nikro_image_effects/form-demo - to play with the image effects demo.
This is a small demo:
- It allows users to select a format that they want - this applies initial cropping, pre-defined image-style (derivative).
- It allows users to enter a Headline (which will be overlaid on the bottom of the image).
- It allows users to select a color for text and a color for the background of the text.
- It will overlay a Favicon from my website, to the top-right corner.
- Also, I used different fonts for different image formats (facebook vs twitter).
I hope this gives a general idea of how this can be used and for what. One can even use this to craft amazing NFT collections (imagine overlaying various traits) 😉
Note - this was a quick and dirty implementation, if you spot anything that can be improved, please let me know (or, make a fork and a pull-request).
💡 Inspired by this article?
If you found this article helpful and want to discuss your specific needs, I'd love to help! Whether you need personal guidance or are looking for professional services for your business, I'm here to assist.
Comments:
Feel free to ask any question / or share any suggestion!