Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resize() does not properly handle orientation metadata #4047

Closed
3 tasks done
Etheryte opened this issue Mar 31, 2024 · 5 comments
Closed
3 tasks done

resize() does not properly handle orientation metadata #4047

Etheryte opened this issue Mar 31, 2024 · 5 comments
Labels

Comments

@Etheryte
Copy link

Possible bug

Is this a possible bug in a feature of sharp, unrelated to installation?

  • Running npm install sharp completes without error.
  • Running node -e "require('sharp')" completes without error.

If you cannot confirm both of these, please open an installation issue instead.

Are you using the latest version of sharp?

  • I am using the latest version of sharp as reported by npm view sharp dist-tags.latest.

If you cannot confirm this, please upgrade to the latest version and try again before opening an issue.

If you are using another package which depends on a version of sharp that is not the latest, please open an issue against that package instead.

What is the output of running npx envinfo --binaries --system --npmPackages=sharp --npmGlobalPackages=sharp?

  System:
    OS: macOS 13.4.1
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 16.50 GB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v20.11.0/bin/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.0/bin/npm
    pnpm: 8.15.5 - ~/.nvm/versions/node/v20.11.0/bin/pnpm
  npmPackages:
    sharp: ^0.33.3 => 0.33.3

What are the steps to reproduce?

Given a certain jpg file (attached below) that uses orientation metadata to orient the image, using resize() on the image causes it to be rotated 90 degrees.

Screenshot 2024-03-31 at 15 08 44

The problem replicates with a mere sharp('./bugged-in.jpg').resize(300).toFile('./bugged-out.jpg').

Reading out the file metadata, for the bugged file we get:

{
  format: 'jpeg',
  width: 6240,
  height: 4160,
  space: 'srgb',
  channels: 3,
  depth: 'uchar',
  density: 72,
  chromaSubsampling: '4:2:0',
  isProgressive: false,
  resolutionUnit: 'inch',
  hasProfile: false,
  hasAlpha: false,
  orientation: 8,
  exif: <Buffer 45 78 69 66 00 00 49 49 2a 00 08 00 00 00 0d 00 0f 01 02 00 09 00 00 00 aa 00 00 00 10 01 02 00 06 00 00 00 b4 00 00 00 12 01 03 00 01 00 00 00 08 00 ... 65416 more bytes>,
  xmp: <Buffer 3c 3f 78 70 61 63 6b 65 74 20 62 65 67 69 6e 3d 27 ef bb bf 27 20 69 64 3d 27 57 35 4d 30 4d 70 43 65 68 69 48 7a 72 65 53 7a 4e 54 63 7a 6b 63 39 64 ... 12205 more bytes>
}

To confirm that the issue lies with the orientation field, I took the same image, rotated it 90 degrees left in the macOS Preview app, saved it, rotated it 90 degrees to the right, and saved it again to normalize the orientation.

For the working file, we get:

{
  format: 'jpeg',
  width: 4160,
  height: 6240,
  space: 'srgb',
  channels: 3,
  depth: 'uchar',
  density: 72,
  chromaSubsampling: '4:2:0',
  isProgressive: false,
  resolutionUnit: 'inch',
  hasProfile: false,
  hasAlpha: false,
  orientation: 1,
  exif: <Buffer 45 78 69 66 00 00 4d 4d 00 2a 00 00 00 08 00 0b 01 0f 00 02 00 00 00 09 00 00 00 92 01 10 00 02 00 00 00 06 00 00 00 9c 01 12 00 03 00 00 00 01 00 01 ... 1272 more bytes>,
  iptc: <Buffer 50 68 6f 74 6f 73 68 6f 70 20 33 2e 30 00 38 42 49 4d 04 04 00 00 00 00 02 47 1c 01 5a 00 03 1b 25 47 1c 02 00 00 02 00 02 1c 02 50 00 ff 20 20 20 20 ... 588 more bytes>,
  xmp: <Buffer 3c 3f 78 70 61 63 6b 65 74 20 62 65 67 69 6e 3d 22 ef bb bf 22 20 69 64 3d 22 57 35 4d 30 4d 70 43 65 68 69 48 7a 72 65 53 7a 4e 54 63 7a 6b 63 39 64 ... 3253 more bytes>
}

What is the expected behaviour?

Resizing the image should either respect the orientation and/or the orientation should be normalized so the image is not rotated when it's resized.

Please provide a minimal, standalone code sample, without other dependencies, that demonstrates this problem

The issue replicates with sharp('./bugged-in.jpg').resize(300).toFile('./bugged-out.jpg').

For your convenience, I've also made a small repo which is a self contained replication of the bug: https://github.com/Etheryte/sharp-demo

Please provide sample image(s) that help explain this problem

Bugged image: https://github.com/Etheryte/sharp-demo/blob/master/bugged-in.jpg
Working image: https://github.com/Etheryte/sharp-demo/blob/master/working-in.jpg

@Etheryte
Copy link
Author

Since Sharp uses libvips for image processing, I went ahead and tried it out natively as well. Running libvips from the command line, the issue is not present and orientation is handled correctly.

$ vips resize bugged-in.jpg out.jpg 0.1

So it seems like the issue stems from Sharp.

@lovell lovell added question and removed triage labels Mar 31, 2024
@lovell
Copy link
Owner

lovell commented Mar 31, 2024

Please see #2297 (comment)

@Etheryte
Copy link
Author

@lovell Thanks for the hint, that is a functional workaround for the problem. However, I would argue that this is fundamentally still a bug. If you think about it from a layman's perspective, when you open an image in paint and change its size, you wouldn't expect it to suddenly become rotated — likewise here. While I understand the technical rationale behind it, I think from an end user perspective it doesn't make sense as the default. Intuitively, rotating by zero degrees should be a no-op, it shouldn't be a prerequisite for resizing images.

That being said, I'm sure you have good reasons for the design choices and I'm just a random developer doing a drive-by on your library. Just my two cents for thought.

@lovell
Copy link
Owner

lovell commented Mar 31, 2024

when you open an image in paint and change its size, you wouldn't expect it to suddenly become rotated

sharp is a library not a UI. It will not rotate images unless told to. The documented default behaviour is to remove EXIF metadata.

@lovell
Copy link
Owner

lovell commented Apr 29, 2024

I hope this information helped. Please feel free to re-open with more details if further assistance is required.

@lovell lovell closed this as completed Apr 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants