John Svensson: How to dynamically create image styles derivatives – Part 1

Published on February 14, 2019

Annertech: Annertech: Web Agency of the Year

Annertech: Web Agency of the Year My fingers are trembling typing this. I can’t believe it. This morning everyone in Annertech land is thinking “did that really just happen?” It appears it did, we are the web agency of the year! Last night, to top off the other three awards we won – best arts […]

Flickr: Registration Desk – Tuesday – DrupalCon Dublin 2016

comprock posted a photo: The Drupal community is one of the largest open source communities in the world. We’re developers, designers, strategists, coordinators, editors, translators, and more. Each year, we meet at DrupalCamps, meetups, and other events in more than 200 countries. But once a year, our community comes together in a European city for […]

Flickr: Sprint Lounge – Tuesday – DrupalCon Dublin 2016

comprock posted a photo: The Drupal community is one of the largest open source communities in the world. We’re developers, designers, strategists, coordinators, editors, translators, and more. Each year, we meet at DrupalCamps, meetups, and other events in more than 200 countries. But once a year, our community comes together in a European city for […]

Flickr: Tuesday – DrupalCon Dublin 2016

comprock posted a photo: The Drupal community is one of the largest open source communities in the world. We’re developers, designers, strategists, coordinators, editors, translators, and more. Each year, we meet at DrupalCamps, meetups, and other events in more than 200 countries. But once a year, our community comes together in a European city for […]

Flickr: David & Paul – Scout masters – Wednesday – DrupalCon Dublin 2016

comprock posted a photo: The Drupal community is one of the largest open source communities in the world. We’re developers, designers, strategists, coordinators, editors, translators, and more. Each year, we meet at DrupalCamps, meetups, and other events in more than 200 countries. But once a year, our community comes together in a European city for […]

Flickr: Jam interview – Wednesday – DrupalCon Dublin 2016

comprock posted a photo: The Drupal community is one of the largest open source communities in the world. We’re developers, designers, strategists, coordinators, editors, translators, and more. Each year, we meet at DrupalCamps, meetups, and other events in more than 200 countries. But once a year, our community comes together in a European city for […]

Flickr: Sprinters wanted – Wednesday – DrupalCon Dublin 2016

comprock posted a photo: The Drupal community is one of the largest open source communities in the world. We’re developers, designers, strategists, coordinators, editors, translators, and more. Each year, we meet at DrupalCamps, meetups, and other events in more than 200 countries. But once a year, our community comes together in a European city for […]

Flickr: Sprint Lounge – Wednesday – DrupalCon Dublin 2016

comprock posted a photo: The Drupal community is one of the largest open source communities in the world. We’re developers, designers, strategists, coordinators, editors, translators, and more. Each year, we meet at DrupalCamps, meetups, and other events in more than 200 countries. But once a year, our community comes together in a European city for […]

Leopathu: Dynamic Block Weight in Drupal 8

In such a time, i want to place blocks in sidebar region with the dynamic weight. It means the blocks should render in different position for each page request. I have searched and tried lots of method but unfortunately i can’t find proper method to do that. So i have decided to do that with […]

Agiledrop.com Blog: AGILEDROP: Drupal‘s path from 4.0 to 8.0

Last time we guided you through early beginnings of Drupal. We explained how all started and how first versions of Drupal were made. This time we will look how this open-source content-management framework evolved from its fourth to its latest, eight version. Drupal 4.0 Drupal’s fourth version was released on 15. 6. 2002. It became […]

Flickr: Wednesday – DrupalCon Dublin 2016

comprock posted a photo: The Drupal community is one of the largest open source communities in the world. We’re developers, designers, strategists, coordinators, editors, translators, and more. Each year, we meet at DrupalCamps, meetups, and other events in more than 200 countries. But once a year, our community comes together in a European city for […]

OStatic: Web Publishing and Development: Free Tools Abound

Are you involved in DevOps and web development, or are you aiming to be? If so, you’re probably very aware of many of the tools from the open standards and open source arenas that can make your work easier. Still, these are always spreading out at a fast clip and there are some applications and […]

Three months ago I wrote an article on how to Create Image Styles and Effects programmatically and today we’re following up on that article but introducing on how we can do that dynamically.
So, essentially what we would like to do is that we display an image, where we can adjust the way the image is outputted, given a height, width or aspect ratio etc.
Please bear in mind that all code provided in this article are experimental and does not yet cover things like access control, etc in this part.
Let’s take a look at the service Unsplash.com. Its basically a free image bank with high quality images submitted by awesome freelancers and professionals that you can use for free.

Image by Eric Ward
The URL for the image above is the following:
https://images.unsplash.com/photo-1499365094259-713ae26508c5?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=26d4766855746c603e3d42aaec633144&auto=format&fit=crop&w=500&q=60
The parts we’re actually interested in are: &auto=format&fit=crop&w=500&q=60 we can adjust them as we like and the image is displayed differently, i.e. changing the width of the earlier image to a smaller one:

Alright, that’s what we would like to do in Drupal Support Service 8. This article will be very iteratively, we’ll rewrite the same code over and over until we get what we want. We’ll notice issues and problems that we will deal with through out the article.
Prepare an environment to work in
We’ll use a fresh Drupal Support Service 8.6.x installation.
To quickly scaffold some boilerplate code I’m going to use Drupal Support Service Console.
First let’s create a custom module where we can put our code and logic in:
$ vendor/bin/drupal generate:module

I’ll name the module dynamic_image_viewer
dynamic_image_viewer.info.yml
name: ‘Dynamic Image Viewer’
type: module
description: ‘View an image dynamically’
core: 8.x
package: ‘Custom’

Next we need some images to work with, we’ll use the core Media module for that. So let’s enable that module:
vendor/bin/drupal module:install media
Now we can add some images. Go to Content >> Media >> Add media.

Implementing a Controller to display the image
The first step is to create a controller that will render the Media image to the browser. Again we’ll use Drupal Support Service Console for a controller scaffold: vendor/bin/drupal generate:controller
We’ll create a route on /image/{media} where Media will accept an media ID that due to Drupal Support Services parameter upcasting will give us a media instance in the controller method arguments. Doing this, if a invalid media ID is passed in the URL a 404 page is shown for us. Neat!
So we’ll modify the generated controller slightly to this:
src/Controller/ImageController.php
<?php

namespace Drupal Support Servicedynamic_image_viewerController;

use Drupal Support ServiceCoreControllerControllerBase;
use Drupal Support ServicemediaMediaInterface;

/**
* Class ImageController.
*/
class ImageController extends ControllerBase {

/**
* Show an image.
*
* @param MediaInterface $media
*
* @return array
*/
public function show(MediaInterface $media) {
return [
‘#type’ => ‘markup’,
‘#markup’ => $media->id(),
];
}

}

And the routing file looks like this: dynamic_image_viewer.routing.yml
dynamic_image_viewer.image_controller_show:
path: ‘/image/{media}’
defaults:
_controller: ‘Drupal Support Servicedynamic_image_viewerControllerImageController::show’
_title: ‘show’
requirements:
_permission: ‘access content’

If we install the module, vendor/bin/drupal module:install dynamic_image_viewer and hit the URL /image/1 we should see a page with the ID being outputted.
Render the original image
Ok. Currently nothing is rendered, so what we’ll do is that we render the uploaded original image first.
To serve the file we’ll use BinaryFileResponse. So let’s update the ImageController::show method.
We’ll also import the class in the top of the file:
use SymfonyComponentHttpFoundationBinaryFileResponse;
/**
* Show an image.
*
* @param MediaInterface $media
*
* @return BinaryFileResponse
*/
public function show(MediaInterface $media) {
$file = $media->field_media_image->entity;

$uri = $file->getFileUri();
$headers = file_get_content_headers($file);

$response = new BinaryFileResponse($uri, 200, $headers);

return $response;
}

So what we do here is that we grab the File entity from the field_media_image field on the Media image bundle. We get the URI and, using the file_get_content_headers we get the proper headers. Finally we serve the file back with the proper headers to the viewer.
And if we hit the URL again:

Before we continue, we should note some things that we’ll get back to later:

What if the media ID is not a Media image?
The user can still access the media even if its unpublished.
What about cache?

Let’s make a hard-coded image derivative
To modify the image, we’ll create a new instance of ImageStyle and add an image effect.
Let’s update the ImageController::show method again:
/**
* Show an image.
*
* @param MediaInterface $media
*
* @return BinaryFileResponse
*/
public function show(MediaInterface $media) {
$file = $media->field_media_image->entity;

$image_uri = $file->getFileUri();

$image_style = ImageStyle::create([
‘name’ => uniqid(), // @TODO This will create a new image derivative on each request.
]);
$image_style->addImageEffect([
‘id’ => ‘image_scale_and_crop’,
‘weight’ => 0,
‘data’ => [
‘width’ => 600,
‘height’ => 500,
],
]);

$derivative_uri = $image_style->buildUri($image_uri);

$success = file_exists($derivative_uri) || $image_style->createDerivative($image_uri, $derivative_uri);

$response = new BinaryFileResponse($derivative_uri, 200);

return $response;
}

So what we do here is that we create a new ImageStyle entity, but we don’t save it. We give it a unique name (but we’ll change that soon) and then add we add an image effect that scale and crops the image to a width of 600 and height 500.
And then we build the derivate uri and if the file exists already, we’ll serve it and if not we’ll create a derivative of it.
There is one big problem here. Since we use a unique id as name of the image style we’ll generate a new derivative on each request which means that the same image will be re-generated over and over. To solve it for now, we could just change the
$image_style = ImageStyle::create([
‘name’ => uniqid(), // @TODO This will create a new image derivative on each request.

to a constant value, but I left it for that reason intentionally. The reason is that I want to explicitily tell us that we need to do something about that and here is how:
If we look back at the URI from Unsplash earlier &auto=format&fit=crop&w=500&q=60, these different keys are telling the code to derive the image in a certain way.
We’ll use the provided keys and combine them some how in to a fitting name for the image style. For instance, we could just take the values and join them with a underscore.
Like so:
format_crop_500_60 and we’ll have a unique string. If the user enters the same URL with the same parameters we’ll be able to find the already existing derivative or if its another image, we’ll create a derivative for it.
You’ll also notice that I removed the $headers = file_get_content_headers($file); it is because those headers are not the correct ones for ur derivatives, we’ll add them back soon.
Dynamic width and height values
On our second iteration of the code we’ll now add the width and height parameters, and we’ll also change the name of the image style to be dynamic.
Again, we’ll update ImageController::show
We’ll also import a class by adding use SymfonyComponentHttpFoundationRequest; in the top of the file.
/**
* Show an image.
*
* @param Request $request
* @param MediaInterface $media
*
* @return BinaryFileResponse
*/
public function show(Request $request, MediaInterface $media) {

$query = $request->query;

$width = (int) $query->get(‘width’, 500);
$height = (int) $query->get(‘height’, 500);

// We’ll create the image style name from the provided values.
$image_style_id = sprintf(‘%d_%d’, $width, $height);

$file = $media->field_media_image->entity;

$image_uri = $file->getFileUri();

$image_style = ImageStyle::create([
‘name’ => $image_style_id,
]);
$image_style->addImageEffect([
‘id’ => ‘image_scale_and_crop’,
‘weight’ => 0,
‘data’ => [
‘width’ => $width,
‘height’ => $height,
],
]);

// … Rest of code

First we updated the method signature and injected the current request. Next, we’ll get the width and height parameters if they exist and if not we fallback to something. We’ll build an image style name of these dynamic values. With this we updated the name of the ImageStyle instance we create which makes sure that we can load the same derivative if the user hits the same URL. Finally we updated the width and height in the image effect.
Let’s add the proper headers back
Here is the updated ImageController::show and current file:
src/Controller/ImageController.php
<?php

namespace Drupal Support Servicedynamic_image_viewerController;

use Drupal Support ServiceCoreControllerControllerBase;
use Drupal Support ServicemediaMediaInterface;
use SymfonyComponentHttpFoundationBinaryFileResponse;
use Drupal Support ServiceimageEntityImageStyle;
use SymfonyComponentHttpFoundationRequest;
use Drupal Support ServiceCoreImageImageFactory;
use SymfonyComponentDependencyInjectionContainerInterface;

/**
* Class ImageController.
*/
class ImageController extends ControllerBase {

/**
* The image factory.
*
* @var Drupal Support ServiceCoreImageImageFactory
*/
protected $imageFactory;

/**
* Constructs a ImageController object.
*
* @param Drupal Support ServiceCoreImageImageFactory $image_factory
* The image factory.
*/
public function __construct(ImageFactory $image_factory) {
$this->imageFactory = $image_factory;
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get(‘image.factory’)
);
}
/**
* Show an image.
*
* @param Request $request
* @param MediaInterface $media
*
* @return BinaryFileResponse
*/
public function show(Request $request, MediaInterface $media) {

$query = $request->query;

$width = (int) $query->get(‘width’, 500);
$height = (int) $query->get(‘height’, 500);

$image_style_id = sprintf(‘%d_%d’, $width, $height);

$file = $media->field_media_image->entity;

$image_uri = $file->getFileUri();

$image_style = ImageStyle::create([
‘name’ => $image_style_id,
]);
$image_style->addImageEffect([
‘id’ => ‘image_scale_and_crop’,
‘weight’ => 0,
‘data’ => [
‘width’ => $width,
‘height’ => $height,
],
]);

$derivative_uri = $image_style->buildUri($image_uri);

$success = file_exists($derivative_uri) || $image_style->createDerivative($image_uri, $derivative_uri);

$headers = [];

$image = $this->imageFactory->get($derivative_uri);
$uri = $image->getSource();
$headers += [
‘Content-Type’ => $image->getMimeType(),
‘Content-Length’ => $image->getFileSize(),
];

$response = new BinaryFileResponse($uri, 200, $headers);

return $response;
}

}

First we added a new dependency to our controller Drupal Support ServiceCoreImageImageFactory which allows us to construct an Image instance, where we can get meta data from the image, but also gives us a unified interface to apply things to our image. For instance, we could desaturate the image by doing $image->desaturate(); and then resave the file. Fow now we’re only using it to retrieve the meta data. We’ll take advantage of that in the next part, when we refactor some of the written code and add more flexibility to what we can dynamically output.
If we hit the url and add both the width and height parameters we’ll get something like this:

In the up coming article we’ll take a better look at what we have, what we miss (access control, what if a user hits the same URL at the same time), adding more effects, and exploring the use of the Image and toolkit APIs more in depth.
We’ll most likely remove adding image effects through ImageStyles and only use the image style for creating derivates that we can we can later apply changes with the toolkit API.
If you want to continue on your own, take a look at ImageStyleDownloadController.php file in core which contains a lot of code that we can re-use.

Source: New feed

REQUEST FOR PROPOSAL

Need a quick project proposal?

Submit the RFP form below and we will send you a project proposal in 48 hours. If you like what you see, we can schedule a call to discuss the project in greater detail.

Step 1 of 2

  • Contact Information

* Subject to reasonable use. Small fixes and updates must be requested one at a time and take no more than 30 minutes. Only mission-critical tasks are addressed on weekends.

Shopping Cart
There are no products in the cart!
Continue Shopping
0