Es un poco extraño para mí la forma en que se comporta la transmisión en algún momento. La tarea simple en el trabajo es extraer una imagen de S3 y transformarla usando una biblioteca nítida; finalmente cargue la imagen redimensionada de nuevo a S3. Puedo ver la imagen redimensionada en S3 pero el código falla con un error.
Aquí hay un fragmento de código que hace todo el trabajo:
// 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
Aquí está el error que recibo del código anterior:
{ "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)" ] }
Cualquier sugerencia muy apreciada.
Está intentando hacer algo que actualmente es un poco difícil con node-sharp: consulte https://github.com/lovell/sharp/issues/236
En resumen, el problema es que .metadata()
requiere leer la imagen completa en la memoria (como un búfer) para calcular los valores . Además de eso, el cambio de tamaño relativo (porcentaje del tamaño original) crea una dependencia de datos : debe conocer las dimensiones de la imagen antes de poder calcular el ancho y el alto objetivo.
Teniendo en cuenta que está utilizando Sharp como transmisión de transferencia (lectura S3 → cambio de tamaño → escritura S3), llamar a .metadata()
no funcionará, porque ocurre demasiado tarde: debe configurar las opciones de cambio de tamaño antes de canalice los datos (para que el proceso de cambio de tamaño pueda conocer el tamaño de destino). Al mismo tiempo, primero debe canalizar todos los datos, porque .metadata()
necesita la imagen completa. Las dos necesidades entran en conflicto y hacen que sea imposible tener un único Stream de transferencia de Sharp que haga todo.
Te quedan algunas opciones:
Si no está tratando con imágenes muy grandes, 2. es definitivamente la forma más fácil de implementar esto:
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 });