5

We have a custom module mymodule where we call mymodule_tokens so that we can assign custom token values from the current node. These custom tokens are used to insert values in the Article's MetaTag fields.

Problem

When fetching the default value based on an Image Style (e.g. medium), I cannot get the Height and Width based on the Configuration for the Image Style. How can I get the height and width from the Image Style?

What I have tried, but cannot get the height and width:

function mymodule_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
  $replacements = [];
  $node = $data['node'];
  $node_image = $node->field_image;
  $field_image_style = 'medium';

  if($node_image->isEmpty()) {
    $field_info = FieldConfig::loadByName('node', 'article, 'field_image');
    $image_uuid = $field_info->getSetting('default_image')['uuid'];
    $image = Drupal::service('entity.repository')->loadEntityByUuid('file', $image_uuid);
    $field_image_url = ImageStyle::load($field_image_style)->buildUrl($image->getFileUri());
    $image_style = ImageStyle::load($field_image_style)->getEffects()->getConfiguration();

    // Both give me error messages.
    $image_style_height = $image_style->get('height');
    $image_style_width = $image_style->get('width');
  }
  else {
    $field_image_url = $node_field_image->entity->getFileUri();
    $image_style = ImageStyle::load($field_image_style)->getEffects()->getConfiguration();

    // Both give me error messages.
    $image_style_height = $image_style->get('height');
    $image_style_width = $image_style->get('width');
  }

  foreach($tokens as $name => $original) {
    switch ($name) {
      case 'custom_image_url':
        $replacements[$original] = $field_image_url;
        break;
      case 'custom_image_height':
        $replacements[$original] = $image_style_height;
        break;
      case 'custom_image_width':
        $replacements[$original] = $image_style_width;
       break;
    }
  }    

  return $replacements;
}

Error Message

Error: Call to a member function get() on array in mymodule_tokens()

When printing ImageStyle::load($field_image_style) using Kint this is what we get.

image style array

When printing $image_style, I get the following.

image_style

Using core or contrib tokens rather than custom tokens

Using the following tokens only work when there is a value added to the field_image field, but when the field_image is not populated, the token is not able to return the default image that is populated on the field's settings page.

[node:field_image:medium:height]
[node:field_image:medium:url]
[node:field_image:medium:width]
4
  • Have you installed the Devel sub-module Kint and then did ksm($image_style) to show you the available methods? I doubt that the $image_style object holds the finalized image properties.
    – leymannx
    Commented Jun 20, 2018 at 21:39
  • @leymannx i have updated the question with screenshots using kint() (same output when using ksm()). I can see that in the 'data' array the width and height are there. I wonder if it has to do with being protected. Commented Jun 20, 2018 at 22:12
  • 1
    Everything under "image_scale_and_crop" is protected, so you won't be able to read those values. What are you trying to do, exactly?
    – Kevin
    Commented Jun 20, 2018 at 23:02
  • @Kevin The Image Style medium performs a scale and crop where width => 400 and height => 260. I wanted to query that setting and use it to assign values to the custom tokens (see updated code) rather than hard coding the 400 and 260 in case those values are changed. Tokens such as [node:field_image:medium:height] does not return a value when the field_image is empty, hence the custom tokens. Commented Jun 20, 2018 at 23:36

4 Answers 4

2

You'll need to click on the Available Methods tab and see if there is an method for width and height.

enter image description here

When you click on it, searching for width or height should come up empty. I can tell this by looking at the ImageStyle Class.

But there will be a getEffects() method that you can use, which should contain the width and height.

$style = ImageStyle::load($field_image_style);

So do kint($style->getEffects());

I'll let you take it from here.


If you want to go the $image_style route then you can get the value with

$image_style[0]['1aa.......']['data']['width'];
$image_style[0]['1aa.......']['data']['height'];

PS:

I suggest you read my answer to What is easiest way to debug variables in nodes, views, blocks and page twig templates? to learn how to use kint properly.

1
  • 1
    If you see my answer below, i was able to iterate through it in a loop using the answer you provided. Commented Jun 22, 2018 at 15:45
8

If you wonder how to get the height/width of a rendered image style (not Image style configuration, but the result itself), here's how it's done :

<?php
use Drupal\image\Entity\ImageStyle;

$img_uri = $entity->field_picture->entity->getFileUri();
$image_style = ImageStyle::load('your_image_style');
// $build_url = $image_style->buildUrl($img_uri);
$build_uri = $image_style->buildUri($img_uri);
$image_factory = \Drupal::service('image.factory')->get($build_uri);

$height = $image_factory->getToolkit()->getHeight();
$width = $image_factory->getToolkit()->getWidth();
2
  • This is great. But .. If the image has not been generated beforehand, the $height and $width are 0 / 0 (because the styled image does not actually exist). This does create the correct URL, but the image is not generated until the path is visited. Commented Jun 24, 2022 at 8:21
  • You can check if the image has been generated with file_exists($build_uri). $image_style->createDerivative($img_uri, $build_uri) will create the derivative file.
    – Tim
    Commented Apr 25, 2023 at 13:55
4

No Sssweat's answer inspired this.

I added this before if statement (if($node_image->isEmpty())) to get the height and width.

$image_style_config = (ImageStyle::load('medium')->getEffects()->getConfiguration());

foreach($image_style_config as $config) { 
  if(isset($config['data'])) {
    if(isset($config['data']['height'])) {
      $image_style_height = $config['data']['height'];
    }
    if(isset($config['data']['width'])) {
      $image_style_width = $config['data']['width'];
    }
  }
}
0

I didn't really like the approach to get the dimensions through the effects array, hence these don't represent the dimensions of the final generated image.

I found a similar approach to @JFC's approach here, but without the need of the images needing to be generated beforehand:

$image = \Drupal::service('image.factory')->get($file->getFileUri());
$image_style = \Drupal\image\Entity\ImageStyle::load('gallery_large');
// Set source image dimensions.
$dimensions = [
  'width' => $image->getWidth(),
  'height' => $image->getHeight(),
];
// After calling this, the $dimensions array will contain new dimensions.
$image_style->transformDimensions($dimensions, $file->getFileUri());

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.