Sharp图像库在调整大小时会旋转图像吗?

66
使用 node.js 的锐化图像调整库 https://github.com/lovell/sharp 时,图像会被旋转。
我没有写 .rotate() 的代码,为什么它会被旋转并如何停止旋转?
我正在使用 AWS 提供的 serverless-image-resizing 示例:https://github.com/awslabs/serverless-image-resizing,该示例使用 lambda 在缩略图不存在时动态调整图像大小。
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))

原始大图像:

输入图像描述

调整大小的图像:请注意,它也已经被旋转:

输入图像描述

6个回答

107

问题实际上是这样的:当您调整图像大小时,Exif数据会丢失。Exif数据包括图像的正确方向,即哪个方向是朝上。

幸运的是,Sharp确实具有保留Exif数据的功能,.withMetadata()。因此,上面的代码需要更改为:

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.

我有一个不相关的问题,但是我找不到任何信息。我想旋转一个特定角度的图像(不是90的倍数)。我知道libvips可以提供这个功能,这可能是它没有的原因。有什么建议可以实现这一点(即使是在纯js中)? - Jeremy Chone
9
您还可以使用rotate()函数:'如果未提供角度,则从EXIF数据中确定。支持镜像操作,可能会推断出翻转操作的使用。' - James T
4
我是唯一一个认为这种细节应该成为默认设置的人吗? - U.Savas
3
我建议使用rotate()解决方案,因为EXIF数据可能包含有关原始照片的潜在私人信息。如果您的唯一目标是修复旋转,则不需要通过将所有这些私人数据转发到调整大小的版本中来泄漏它们。 - Zero Trick Pony

88

另一种解决方案是在调用resize之前实际调用.rotate()。这将根据EXIF数据自动定向图像。

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

请参阅文档以获取更多详细信息。

这样就不需要保留原始元数据,从而使图像总体大小更小。


1
非常好,谢谢!我之前在文档中没有看到这个,所以一直在使用另一个库来旋转,然后再用Sharp进行调整大小。 - Carlino Gonzalez
1
使用 rotate 可以将 toFormat("png") 保持原样。 - Tomasz Czechowski
1
由于某种原因,如果我使用“withMetadata()”方法并尝试仅调整宽度,则会将高度而非宽度调整为指定值。但是这种方法完美地解决了问题。 - Lahiru Chandima
1
这种方法似乎能够产生准确的宽度和高度,不像使用withMetadata()方法那样。 - Andrew Clark
2
顺序很重要。我发现 resize(...).rotate() 能够正常工作,而 rotate().resize(...) 对于某些图像无法正常工作。 - Anton Ivinskyi
显示剩余4条评论

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

使用(.withMetadata()),可以防止图像旋转。
此外,您只需要传递宽度参数,不需要高度。

1
我以与AWS Serverless Image Handler相关的方式修复了此问题,而不更改代码。 我正在编辑列表中传递"rotate":null
阅读最新(5.2.0)代码时,看起来他们尝试修复了这个问题,但在我添加"rotate":null之前,它仍然无法正常工作。
这是Github上的一个相关问题:https://github.com/awslabs/serverless-image-handler/issues/236

0

0

针对 Serverless Image Handler 5.0 的更新答案,使用 CloudFormation Stack 模板在 10/2020 部署:

我在 image-handler.js 的第 50 行添加了 .rotate(),它就像魔法一样奏效了:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接