NodeJs sharp Image library - Resize using Stream Api 抛出错误 'stream.push() after EOF'
NodeJs sharp Image library - Resize using Stream Api throws error 'stream.push() after EOF'
流有时的行为方式对我来说有点奇怪。工作中的简单任务是从 S3 中提取图像并使用 sharp 库对其进行转换;最后将调整大小的图像上传回 S3。我可以在 S3 中看到调整大小的图像,但代码因错误而失败。
这是完成所有工作的代码片段 -
// Read from S3
const readStream = s3Handler.readStream(params)
// resize Stream
let resizeStream = sharp()
resizeStream
.metadata()
.then((metadata) => {
// Resize the image to a width specified by the `percent` value and output as PNG
sharpOptions = { width: width*(metadata.percent), height: height*(metadata.percent), fit: 'contain' }
resizeStream
.resize(sharpOptions)
.toFormat('png')
.png({ quality: 100, compressionLevel: 5 })
.toBuffer()
//return streamResize.resize(sharpOptions).png().toBuffer()
})
// push to s3
const { writeStream, uploaded } = s3Handler.writeStream({
Bucket: bucket,
Key: key,
Ext: ext,
})
readStream.pipe(resizeStream).pipe(writeStream)
await uploaded
这是我从上面的代码中得到的错误 -
{
"errorType": "Error",
"errorMessage": "stream.push() after EOF",
"code": "ERR_STREAM_PUSH_AFTER_EOF",
"stack": [
"Error [ERR_STREAM_PUSH_AFTER_EOF]: stream.push() after EOF",
" at readableAddChunk (_stream_readable.js:260:30)",
" at Sharp.Readable.push (_stream_readable.js:213:10)",
" at Object.<anonymous> (/var/task/node_modules/sharp/lib/output.js:863:18)"
]
}
非常感谢任何建议。
您正在尝试做一些目前使用 node-sharp 有点困难的事情:请参阅 https://github.com/lovell/sharp/issues/236
简而言之,就是.metadata()
requires reading the entire image into memory (as a Buffer) to compute values的问题。除此之外,相对调整大小(原始大小的百分比)会产生 数据依赖性 - 在计算目标宽度和高度之前,您需要知道图像尺寸。
考虑到您如何将 Sharp 用作直通流(S3 读取 → 调整大小 → S3 写入),对其调用 .metadata()
将不起作用,因为它发生得太晚了:您需要设置在通过管道输入数据之前调整大小选项(以便调整大小过程可能知道目标大小)。同时需要先把所有的数据pipe进去,因为.metadata()
需要完整的图片。这两个需求发生冲突,使得不可能有一个单一的 Sharp 直通流来完成所有事情。
您还有几个选择:
- 放弃基于元数据的动态调整大小并使用静态最大大小(或从其他来源获知的大小 - 由客户端提交,从配置加载等)
- 将整个图像加载到缓冲区中,从中计算元数据,然后调整整个缓冲区的大小
- 使用另一种流式传输技术确定图像大小,该技术不需要一次获取全部数据,运行 获得大小后的管道,like this
如果您不处理非常大的图像,2. 绝对是最简单的实现方式:
const original = (await s3.getObject(getParams).promise()).Body;
const metadata = await sharp(original).metadata();
const resized = await sharp(original).resize({
// NOTE: This computation was bugged in the original example - there's no metadata.percent, it's our own setting.
width: metadata.width * percent,
height: metadata.height * percent,
fit: 'contain'
}).toFormat('png').png({ quality: 100, compressionLevel: 5 }).toBuffer()
await s3.putObject({
...putParams,
Body: resized
});
流有时的行为方式对我来说有点奇怪。工作中的简单任务是从 S3 中提取图像并使用 sharp 库对其进行转换;最后将调整大小的图像上传回 S3。我可以在 S3 中看到调整大小的图像,但代码因错误而失败。
这是完成所有工作的代码片段 -
// Read from S3
const readStream = s3Handler.readStream(params)
// resize Stream
let resizeStream = sharp()
resizeStream
.metadata()
.then((metadata) => {
// Resize the image to a width specified by the `percent` value and output as PNG
sharpOptions = { width: width*(metadata.percent), height: height*(metadata.percent), fit: 'contain' }
resizeStream
.resize(sharpOptions)
.toFormat('png')
.png({ quality: 100, compressionLevel: 5 })
.toBuffer()
//return streamResize.resize(sharpOptions).png().toBuffer()
})
// push to s3
const { writeStream, uploaded } = s3Handler.writeStream({
Bucket: bucket,
Key: key,
Ext: ext,
})
readStream.pipe(resizeStream).pipe(writeStream)
await uploaded
这是我从上面的代码中得到的错误 -
{
"errorType": "Error",
"errorMessage": "stream.push() after EOF",
"code": "ERR_STREAM_PUSH_AFTER_EOF",
"stack": [
"Error [ERR_STREAM_PUSH_AFTER_EOF]: stream.push() after EOF",
" at readableAddChunk (_stream_readable.js:260:30)",
" at Sharp.Readable.push (_stream_readable.js:213:10)",
" at Object.<anonymous> (/var/task/node_modules/sharp/lib/output.js:863:18)"
]
}
非常感谢任何建议。
您正在尝试做一些目前使用 node-sharp 有点困难的事情:请参阅 https://github.com/lovell/sharp/issues/236
简而言之,就是.metadata()
requires reading the entire image into memory (as a Buffer) to compute values的问题。除此之外,相对调整大小(原始大小的百分比)会产生 数据依赖性 - 在计算目标宽度和高度之前,您需要知道图像尺寸。
考虑到您如何将 Sharp 用作直通流(S3 读取 → 调整大小 → S3 写入),对其调用 .metadata()
将不起作用,因为它发生得太晚了:您需要设置在通过管道输入数据之前调整大小选项(以便调整大小过程可能知道目标大小)。同时需要先把所有的数据pipe进去,因为.metadata()
需要完整的图片。这两个需求发生冲突,使得不可能有一个单一的 Sharp 直通流来完成所有事情。
您还有几个选择:
- 放弃基于元数据的动态调整大小并使用静态最大大小(或从其他来源获知的大小 - 由客户端提交,从配置加载等)
- 将整个图像加载到缓冲区中,从中计算元数据,然后调整整个缓冲区的大小
- 使用另一种流式传输技术确定图像大小,该技术不需要一次获取全部数据,运行 获得大小后的管道,like this
如果您不处理非常大的图像,2. 绝对是最简单的实现方式:
const original = (await s3.getObject(getParams).promise()).Body;
const metadata = await sharp(original).metadata();
const resized = await sharp(original).resize({
// NOTE: This computation was bugged in the original example - there's no metadata.percent, it's our own setting.
width: metadata.width * percent,
height: metadata.height * percent,
fit: 'contain'
}).toFormat('png').png({ quality: 100, compressionLevel: 5 }).toBuffer()
await s3.putObject({
...putParams,
Body: resized
});