Sharp: EXIF auto rotating rotates only the image content, not the canvas

Created on 18 Feb 2020  路  2Comments  路  Source: lovell/sharp

What is the output of running npx envinfo --binaries --languages --system --utilities?

System:
    OS: Windows 10 10.0.18363
    CPU: (4) x64 Intel(R) Core(TM) i5-6300HQ CPU @ 2.30GHz
    Memory: 4.79 GB / 11.90 GB
  Binaries:
    Node: 10.17.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.19.1 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
    npm: 6.11.3 - C:\Program Files\nodejs\npm.CMD
  Utilities:
    Git: 2.23.0. - /mingw64/bin/git
  Languages:
    Bash: 4.4.23 - C:\Program Files\Git\usr\bin\bash.EXE
    Java: 1.8.0_131 - /c/Program Files/Java/jdk1.8.0_131/bin/javac
    Perl: 5.26.2 - C:\Program Files\Git\usr\bin\perl.EXE
    Python: 3.5.3 - /c/Users/***/AppData/Local/Programs/Python/Python35/python

What are the steps to reproduce?

  1. Use this EXIF image file as an input
    EXIF-input
  2. Use .resize(metadata.width / 2, metadata.height / 2) to resize the image
  3. Use .rotate() to auto-rotate the image based on the EXIF data
  4. Use .toFile('your-path') to export to the file.
  5. It seems the image content got rotated but the canvas did not, and the image become this now:
    image

What is the expected behaviour?

  • The .rotate() should rotate the whole image including width height. The result should look like this:
    image

Are you able to provide a standalone code sample, without other dependencies, that demonstrates this problem?

    const sharpImage = sharp('./input.jpg', { sequentialRead: true });
    const metadata = await sharpImage.metadata();
    const resizedImage = sharpImage.resize(metadata.width / 2, metadata.height / 2);
    const rotatedImage = resizedImage.rotate();
    const output = await rotatedImage.toFile('./output.jpg');
question

Most helpful comment

Hi, you'll need to break this into two pipelines:

const resizedImage = await sharpImage.resize(metadata.width / 2, metadata.height / 2).toBuffer();
const rotatedImage = sharp(resizedImage).rotate();

For the specific case of halving the dimensions, there's been some previous discussion about an explicit scale option at https://github.com/lovell/sharp/issues/236#issuecomment-305184672

All 2 comments

Hi, you'll need to break this into two pipelines:

const resizedImage = await sharpImage.resize(metadata.width / 2, metadata.height / 2).toBuffer();
const rotatedImage = sharp(resizedImage).rotate();

For the specific case of halving the dimensions, there's been some previous discussion about an explicit scale option at https://github.com/lovell/sharp/issues/236#issuecomment-305184672

@lovell: It works perfectly. Thank you so much!!!

Added:

We should have .withMetadata() in the first pipeline to keep EXIF data for the second pipeline. Otherwise, the second pipeline won't auto-rotate the image.

Thus, the code should be:

const resizedImage = await sharpImage.resize(metadata.width / 2, metadata.height / 2).withMetadata().toBuffer();
const rotatedImage = sharp(resizedImage).rotate();
Was this page helpful?
0 / 5 - 0 ratings