【问题标题】:NodeJs sharp Image library - Resize using Stream Api throws error 'stream.push() after EOF'NodeJs 锐利的图像库 - 使用 Stream Api 调整大小会在 EOF 之后引发错误“stream.push()”
【发布时间】:2021-06-16 03:29:31
【问题描述】:

对我来说,流有时的行为方式对我来说有点奇怪。工作中的简单任务是从 S3 中提取图像并使用Sharp库对其进行转换;最后将调整大小的图像上传回 S3。我可以在 S3 中看到调整大小的图像,但代码失败并出现错误。

这是一个代码 sn-p 完成所有工作 -

// 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.js image-processing sharp


    【解决方案1】:

    您正在尝试使用 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() 将不起作用,因为它发生得太晚了:您需要设置调整大小选项在您输入数据之前(以便调整大小过程可能知道目标大小)。同时,您需要先将所有数据管道化,因为.metadata() 需要完整的图像。这两个需求发生冲突,使得不可能有一个可以做所有事情的 Sharp 直通流。

    你有几个选择:

    1. 退出基于元数据的动态调整大小并使用静态最大大小(或从其他来源已知的大小 - 由客户端提交、从配置加载等)
    2. 将整个图像加载到缓冲区中,从中计算元数据,然后调整整个缓冲区的大小
    3. 使用另一种不需要一次性全部数据的流技术确定图像大小,并在获得大小后运行管道,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
    });
    

    【讨论】:

    • 谢谢罗伯特·卡维克。确实很有帮助。我遵循没有 Stream 的缓冲区方法。它对我有用。
    猜你喜欢
    • 2021-10-07
    • 1970-01-01
    • 2021-04-20
    • 2021-10-25
    • 2018-01-13
    • 2018-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多