I'm working with images in a plugin but getting a bit stuck reading a transformed image.

Given the following code:

$assetTransform = new AssetTransform([
    'mode' => 'stretch',
    'width' =>  64, 
    'height' => 64,
$transformedAsset = $asset->copyWithTransform($assetTransform);
$image = imagecreatefromstring($transformedAsset->getContents());
$width = imagesx($image);

...I would expect the value of $width; to be 64. But it returns the width of the original untransformed image.

Incidentally, the width of $transformedAsset->width returns 64.

Does anyone understand why this occurs?

1 Answer 1


By default, Craft will defer creating image transforms to avoid slowing down page loads. Instead, transforms are queued and executed asynchronously. You can change this behaviour to always generate transforms directly using the generateTransformsBeforePageLoad config setting.

Of course, you don't have control over the config if you're working on a plugin. In this case, you will have to find a way to force Craft to create the transform immediately. Without the config setting, I haven't actually found a straightforward way of doing that. Asset::getUrl() has an optional second parameter for that behaviour – but Asset::copyWithTransform() does not, and Asset::getContents() does not accept a transform argument at all.

If you check the source code for Asset::getUrl(), it uses craft\Services\AssetTransforms:: ensureTransformUrlByIndexModel() to get execute transforms. That returns an asset URL, but under the hood it uses AssetTransforms::_createTransformForAsset which executes the actual image transformation. This method is private unfortunately, so you can't use it directly. But using Asset::getUrl() with $generateNow set to true should suffice to force Craft to generate the transform synchronously. Though you might need to query the asset from the database again to get the actual transformed content.

Sorry this answer isn't complete, but it should point you in the right direction. Maybe also post this as a discussion / feature request to Github, as arguably this is a pretty common requirement.

  • Thanks so much for explaining! 🙌
    – tomkiss
    Aug 3, 2021 at 13:50
  • @tomkiss You're welcome! If the approach outlined here works, I'd be interested in seeing some working examples for this as well, or hearing about points you got stuck on. Craft could definitely use a utility function for generating transforms immediately ...
    – MoritzLost
    Aug 3, 2021 at 14:16
  • 1
    Thanks! Yes, as a bit of background - this was for my first plugin. I was finding multiple related issues using assets and so in the end opted to resize directly in PHP. You can see my plugin over here: github.com/dodecastudio/craft-blurhash It's my first plugin so I'm not quite sure how "correct" I've achieved the result with, but hopefully it's all improvements from here on out.
    – tomkiss
    Aug 8, 2021 at 17:49
  • 1
    @tomkiss Yeah that's probably the easier approach … cool plugin! One thing I noticed is that it's difficult to call the functions provided by the module from PHP since they're tightly coupled to the Twig extension. One use-case I can think of would be to compute blurhashes in the entries save hook and store them for later use in a template. Right now that's difficult because of that coupling. I'd move all functions to a service class and call those from the Twig plugin, allowing users to call the service class functions directly from PHP.
    – MoritzLost
    Aug 9, 2021 at 7:35
  • 1
    Hey @MoritzLost, just wanted to say thanks for your suggestion back in the summer. I moved all the functionality to Service classes, which then made a GraphQL feature request much easier to implement 😀 Credited you, cheers 🙌github.com/dodecastudio/craft-blurhash/releases/tag/v1.1.0
    – tomkiss
    Nov 29, 2021 at 14:47

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.