Make WordPress Core

Opened 3 weeks ago

Closed 3 weeks ago

#65643 closed defect (bug) (fixed)

Media: Fix sideload and finalize for EXIF rotated images

Reported by: adamsilverstein Owned by: adamsilverstein
Priority: normal Milestone: 7.1
Component: Media Version:
Severity: normal Keywords: has-patch has-unit-tests commit
Cc: Focuses:

Description

Part of the client-side media processing feature in 7.1 (see #64919). Follow-up to the sideload dimension validation added in #64798 and the finalize endpoint from #65329.

Steps to reproduce

  1. Enable client-side media processing.
  2. In the editor, upload a JPEG with a quarter-turn EXIF orientation (values 5–8, e.g. a portrait photo taken on a phone).

Result

The upload fails: the image_size=original sideload request returns a 400 with rest_upload_dimension_mismatch.

Cause

In the client-side flow the client uploads the original file unmodified, applies the EXIF rotation itself, then sideloads the rotated file with image_size=original. For quarter-turn orientations the rotated file's width and height are swapped relative to the stored attachment metadata, but validate_image_dimensions() requires exact equality, so the sideload is rejected.

Separately, the original sideload semantics are backwards relative to what core does when it rotates on upload: the rotated file was stored as original_image while the un-rotated upload remained the attachment's main file. wp_create_image_subsizes() does the opposite — it makes the rotated file the main file via _wp_image_meta_replace_original(), keeps the untouched upload as original_image, and resets the stored EXIF orientation to 1.

Proposed fix

PR 12550 (backport of Gutenberg PR 80295, part of Gutenberg issue 77582):

  • Treat an image_size=original sideload like a scaled sideload: the supplied (rotated) file replaces the attachment's main file and the untouched upload is kept as original_image, mirroring _wp_image_meta_replace_original().
  • Accept transposed dimensions when validating an original sideload, since quarter-turn EXIF orientations swap width and height.
  • Reset the stored EXIF orientation to 1 in the finalize endpoint for both original and scaled sub-sizes, as wp_create_image_subsizes() does for its scale and rotate paths, so exif_orientation no longer reports the pre-rotation value once rotation has been applied.
  • Skip original/scaled finalize entries that are missing the file name so a malformed payload cannot blank out the main file metadata.

Includes unit tests, among them a parity test asserting the client-side path produces the same attachment metadata (dimensions, orientation, original_image) as a classic server-side upload of the same EXIF-rotated fixture.

Change History (4)

#1 @adamsilverstein
3 weeks ago

  • Owner set to adamsilverstein
  • Status newassigned

This ticket was mentioned in PR #12550 on WordPress/wordpress-develop by @adamsilverstein.


3 weeks ago
#2

Backport of https://github.com/WordPress/gutenberg/pull/80295 (part of https://github.com/WordPress/gutenberg/issues/77582).

## Problem

In the client-side media upload flow, the client uploads the original file unmodified, applies the EXIF rotation itself, and sideloads the rotated file with image_size=original. For quarter-turn orientations (EXIF 5-8) the rotated file's width and height are swapped relative to the stored metadata, so validate_image_dimensions() rejected the sideload with a 400 (rest_upload_dimension_mismatch) and the upload failed.

The original sideload also stored the rotated file as original_image while the un-rotated upload stayed the attachment's main file, which is backwards relative to what core does when it rotates on upload.

## Solution

  • Treat an image_size=original sideload like a scaled sideload: the supplied (rotated) file replaces the attachment's main file, and the untouched upload is kept as original_image. This mirrors the swap _wp_image_meta_replace_original() performs in wp_create_image_subsizes().
  • Accept transposed dimensions when validating an original sideload.
  • Reset the stored EXIF orientation to 1 in finalize for both original and scaled sub-sizes, as wp_create_image_subsizes() does for its scale and rotate paths, so exif_orientation no longer reports the pre-rotation value once rotation has been applied.
  • Skip original/scaled finalize entries missing the file name so a malformed payload cannot blank out the main file metadata.

Includes a parity test asserting the client-side path produces the same attachment metadata (dimensions, orientation, original_image) as a classic server-side upload of the same EXIF-rotated fixture.

#3 @adamsilverstein
3 weeks ago

  • Keywords commit added

#4 @adamsilverstein
3 weeks ago

  • Resolutionfixed
  • Status assignedclosed

In 62805:

REST API: Fix sideload and finalize for EXIF rotated images.

Fix an issue where client-side media uploads of JPEGs with a quarter-turn EXIF orientation (values 5-8) failed with a 400 rest_upload_dimension_mismatch error, because the rotated file's swapped width and height did not match the stored metadata.

An image_size=original sideload is now handled like a scaled one: the rotated file becomes the attachment's main file and the untouched upload is kept as original_image, matching what core does when it rotates on upload. Finalize also resets the stored EXIF orientation once rotation has been applied.

Follow-up to [61982], [62619].

Props adamsilverstein, andrewserong, ramonjd.
Fixes #65643.

Note: See TracTickets for help on using tickets.