When Converting an Image's Format with Image Styles, Replace the Extension instead of Appending

Created on 9 January 2024, 10 months ago
Updated 26 April 2024, 7 months ago

Problem/Motivation

Currently, when an image is converted to another format by an image style, the new extension is appended to the file name (instead of the new extension replacing the old extension).

Details

The extension is added by Drupal\image\EntityImageStyle::addExtension(), which also does a pretty good job of explaining what is happening and why:

  /**
   * Adds an extension to a path.
   *
   * If this image style changes the extension of the derivative, this method
   * adds the new extension to the given path. This way we avoid filename
   * clashes while still allowing us to find the source image.
   *
   * @param string $path
   *   The path to add the extension to.
   *
   * @return string
   *   The given path if this image style doesn't change its extension, or the
   *   path with the added extension if it does.
   */
  protected function addExtension($path) {
    $original_extension = pathinfo($path, PATHINFO_EXTENSION);
    $extension = $this->getDerivativeExtension($original_extension);
    if ($original_extension !== $extension) {
      $path .= '.' . $extension;
    }
    return $path;
  }

Then, when an image derivative is requested (assuming it doesn't already exist and would then be served by the web server), the request is first processed by Drupal\image\PathProcessor\PathProcessorImageStyles::processInbound(). This path processor rewrites the request URI and appends a query parameter for the original image file.

If the $path parameter passed to ::processInbound() is '/sites/default/files/styles/blog_article_image_1792x784/public/blog/article-image/image.png.webp', then the method will return
'/sites/default/files/styles/blog_article_image_1792x784/public' with the request modified by adding a 'file' query parameter value of 'blog/article-image/image.png.webp'.

The request is later handled by Drupal\image\Controller\ImageStyleDownloadController::deliver(). The $scheme and $image_style parameters are parsed from the path. (In this example, $scheme is 'public' and $image_style is 'blog_article_image_1792x784'.) The 'file' query parameter is used to infer the original file.

As a result, implementing this feature request will require touching several pieces of code. The issue of namespace collisions will also need addressed. E.g. What happens if image.png and image.jpg are both uploaded? Both can't use the image.webp namespace.

As is detailed in ๐Ÿ› ImageStyleDownloadController::deliver() infers source image when generating derivatives with image format conversion Active , Drupal\image\Controller\ImageStyleDownloadController::deliver() can incorrectly infer the source image, and, as a result, render an incorrect image.

Because this behavior is intentional, I'm filing this issue as a feature request instead of a bug.

Steps to reproduce

  1. Install a vanilla Drupal site with the 'Standard' profile.
  2. Install Media & Media Library modules.
  3. Navigate to /admin/config/media/media-settings and enable the 'Standalone media URL' setting.
  4. Ensure the 'Default' view mode for the 'Image' media type is configured to render the 'Large' image style (/admin/structure/media/manage/image/display).
  5. Update the 'Large' image style to convert to 'WebP' (/admin/config/media/image-styles/manage/large).
  6. Upload a PNG image (e.g. image.png) to a media entity (/media/1).
  7. Load /media/1 and observe the image file name is image.png.webp and not image.webp.

Proposed resolution

TBD

Remaining tasks

TBD

User interface changes

TBD

API changes

TBD

Data model changes

TBD

Release notes snippet

TBD

๐Ÿ› Bug report
Status

Active

Version

11.0 ๐Ÿ”ฅ

Component
Image moduleย  โ†’

Last updated 10 days ago

Created by

๐Ÿ‡บ๐Ÿ‡ธUnited States Chris Burge

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

Merge Requests

Comments & Activities

Production build 0.71.5 2024