Skip to content

A JPEG with an EXIF orientation is recorded with its width and height swapped #18383

Description

@franknoel

Describe the Bug

A JPEG with an EXIF orientation of 5 to 8, as a phone writes for a portrait photo, is uploaded to a collection with upload: true and no resize, format or trim option. Payload stores the file as uploaded, which is right. But the document records the width and height of the stored pixels, not the size a browser shows.

A photo stored 1200×800 with orientation 6 is shown 800×1200 by browsers, by sharp's rotate() and by image optimizers. Its document says width: 1200, height: 800. A page that sizes the image from its document, for example with next/image, shows it stretched.

The cause is in packages/payload/src/uploads/getImageSize.ts. It reads width and height from sharp(file).metadata(), and sharp gives these before the turn. The size after the turn is in metadata().autoOrient. Without sharp, the size comes from the file's header, with the same result.

Payload turns the picture itself only when it re-encodes the file (.rotate() in generateFileData.ts). Then the stored file and the record agree. A file stored as uploaded keeps its orientation tag, and the record keeps the size before the turn.

Expected: the document records the size the picture is shown at, 800×1200 here.

Related:

Link to the code that reproduces this issue

https://github.com/franknoel/payload-exif-orientation-size

Reproduction Steps

  1. Clone the repository. cp .env.example .env, then fill in DATABASE_URL and PAYLOAD_SECRET.
  2. pnpm install
  3. pnpm check

The script empties the Media collection, uploads each file of fixtures/ with the local API, and prints the recorded size next to the size a viewer shows. Both fixtures show the same portrait picture:

ok        upright.jpg  orientation none  recorded 800x1200  shown 800x1200
MISMATCH  turned.jpg   orientation 6     recorded 1200x800  shown 800x1200

The same happens over REST, the way the admin uploads: with pnpm dev running, a POST /api/media with fixtures/turned.jpg answers with width: 1200, height: 800.

Which area(s) are affected?

area: core

Environment Info

Binaries:
  Node: 24.21.0
  npm: 11.19.0
  Yarn: 1.22.22
  pnpm: 9.15.9
Relevant Packages:
  payload: 3.90.2
  next: 16.3.3
  @payloadcms/db-mongodb: 3.90.2
  @payloadcms/graphql: 3.90.2
  @payloadcms/next/utilities: 3.90.2
  @payloadcms/richtext-lexical: 3.90.2
  @payloadcms/translations: 3.90.2
  @payloadcms/ui/shared: 3.90.2
  react: 19.2.6
  react-dom: 19.2.6
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.6.0
  Available memory (MB): 32768
  Available CPU cores: 10

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bugarea: coreCore Payload functionalitystatus: needs-triagePossible bug which hasn't been reproduced yetv3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions