62

When using the sharp image resize library https://github.com/lovell/sharp for node.js, the image is being rotated.

I have no code thats says .rotate(), so why is it being rotated and how can I stop it from rotating?

I'm using the serverless-image-resizing example provided by AWS: https://github.com/awslabs/serverless-image-resizing that uses lambda to resize images on the fly if the thumbnail does not exist

S3.getObject({Bucket: BUCKET, Key: originalKey}).promise()
.then(data => Sharp(data.Body)
      .resize(width, height)
      .toFormat('png')
      .toBuffer()
    )
.then(buffer => S3.putObject({
        Body: buffer,
        Bucket: BUCKET,
        ContentType: 'image/png',
        Key: key,
      }).promise()
    )
.then(() => callback(null, {
        statusCode: '301',
        headers: {'location': `${URL}/${key}`},
        body: '',
      })
    )
.catch(err => callback(err))

Original large image:

enter image description here

Resized image: note it has been rotated as well:

enter image description here

JK.
  • 21,477
  • 35
  • 135
  • 214

6 Answers6

102

The problem actually turned out to be this: when you resize an image, the exif data is lost. The exif data includes the correct orientation of the image, ie which way is up.

Fortunately sharp does have a feature that does retain the exif data, .withMetadata(). So the code above needs to be changed to read:

S3.getObject({Bucket: BUCKET, Key: originalKey}).promise()
.then(data => Sharp(data.Body)
      .resize(width, height)
      .withMetadata() // add this line here
      .toBuffer()
    )

(Note that you also need to remove the .toFormat('png') call because png does not have the same support for exif that jpeg does)

And now it works properly, and the resized image is the correct way up.

JK.
  • 21,477
  • 35
  • 135
  • 214
  • I have a unrelated question, but I cannot find any information. I would like to rotate an image of a specific angle (not multiple of 90). I understand libvips does provide that, which is probably the reason does not. Any suggestions to accomplish that (even if it is in pure js) ? – Jeremy Chone Jun 01 '18 at 17:29
  • 8
    You could also use [`rotate()`](http://sharp.pixelplumbing.com/en/stable/api-operation/#rotate): 'If no angle is provided, it is determined from the EXIF data. Mirroring is supported and may infer the use of a flip operation.' – James T Jun 08 '18 at 10:08
  • 4
    Am I the only one who think this kind of details should be default... – U.Savas Apr 26 '21 at 17:28
  • 3
    I would recommend the rotate() solution over this, since EXIF data can contain potentially private information about the original photograph. If your only goal is to fix rotation, you don't need to leak all this private data by forwarding all of it into the resized version. – Zero Trick Pony Feb 21 '22 at 00:26
88

The alternative solution is to actually call .rotate() before resize. This will auto-orient the image based on the EXIF data.

.then(data => Sharp(data.Body)
      .rotate()
      .resize(width, height)
      .toBuffer()
    )

More details in the docs.

This way you don't need to retain the original metadata, keeping the overall image size smaller.

mihai
  • 37,072
  • 9
  • 60
  • 86
2
 const data = await sharp(file_local)
    .resize({
      width: px,
     
  })
    .jpeg({
      quality: quality,
      progressive: true,
      chromaSubsampling: "4:4:4",
    })
    .withMetadata()
    .toFile(file_local_thumb);

Using the (.withMetadata()), to prevent rotation of image.

Aditional you can pass the width only parameter, you dont need the height.

Zarkys Salas
  • 121
  • 1
  • 4
1

I fixed this in a related way, specific to the AWS Serverless Image Handler, without changing code. I'm passing in "rotate":null in the list of edits.

In reading the latest (5.2.0) code it looks like they tried to fix this, but it still wasn't working for me until I added "rotate":null

Here is a related issue on Github: https://github.com/awslabs/serverless-image-handler/issues/236

g_pass
  • 711
  • 7
  • 15
0

Updated answer for Serverless Image Handler 5.0, deploying with the CloudFormation Stack template as of 10/2020:

I appended .rotate() to line 50 of image-handler.js and it worked like a charm:

const image = sharp(originalImage, { failOnError: false }).rotate();
0

In case you landed here using the Nuxt Image component with IPX provider, this is how I solved it: in the nuxt.config.js file, add this:

  buildModules: [
    [
      '@nuxt/image',
      {
        sharp: {
          withMetadata: true,
        },
      },
    ],
  ],

Note there are more options in the module than the ones that are documented: https://github.com/nuxt/image/blob/61bcb90f0403df804506ccbecebfe13605ae56b4/src/module.ts#L20

Paul Melero
  • 1,323
  • 15
  • 15