Add log message if Imagick was unable to read a file

Created on 2 February 2024, 5 months ago

If you have a very large image file, or a high-resolution image, it's possible that Imagick fails to read that file.
Lets say your server has 512MB of memory and you try to generate a thumbnail image from a 300DPI image with a resolution of 15000 x 15000 pixels and thus also a large filesize.

What happens is, when Drupal tries to create an image style from that image, it fails and you see this in your log messages:
Unable to generate the derived image located at ....

Yes that's good, but you have no idea WHY drupal was unable to generate the derived image.
I figured out that the source is this piece of code in ImagickToolkit.php:

  public function parseFile() {
    $success = FALSE;
    try {
      $resource = new Imagick();
      $resource->setBackgroundColor(new ImagickPixel('transparent'));
      $resource->readImage($this->getPath());
      $this->setResource($resource);

      $success = TRUE;
    } catch (ImagickException $e) {}

    // cleanup local file if the original was remote
    if ($this->isRemoteUri($this->getPath())) {
      $this->fileSystem->delete($this->getPath());
    }

    return $success;
  }

There are 2 things wrong here I think:
- There is no logging in the catch() part so you never know exactly what went wrong
- It is possible that the $resource (Imagick) object is halfway created before something fails and its never cleared.

I suggest adapting this piece of code to:

  public function parseFile() {
    $success = FALSE;
    $resource = new Imagick();
    try {
      $resource->setBackgroundColor(new ImagickPixel('transparent'));
      $resource->readImage($this->getPath());
      $this->setResource($resource);

      $success = TRUE;
    } catch (ImagickException $e) {
      $resource->clear();
      $this->logger->error('Failed parsing file %file: %message', ['%file' => $this->getPath(),'%message' => $e->getMessage()]);
    }

    // cleanup local file if the original was remote
    if ($this->isRemoteUri($this->getPath())) {
      $this->fileSystem->delete($this->getPath());
    }

    return $success;
  }

That would fix both problems and would generate a helpful watchdog message like this:
Failed parsing file /data/sites/web/mywebsitecom/production/private/assets/images/myverylargeimage.jpg: CacheResourcesExhausted `/data/sites/web/mywebsitecom/production/private/assets/images/myverylargeimage.jpg' @ error/cache.c/OpenPixelCache/4095

Now for those who care they can at least know that Drupal failed to generate the derived image because of Imagick CacheResourcesExhausted

πŸ› Bug report
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡§πŸ‡ͺBelgium flyke

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.69.0 2024