node.jsnode-streamssharp

How to run Sharp transform on readable http stream and write toFile


This question is about the node Sharp library http://sharp.pixelplumbing.com/en/stable/api-input/

Documentation for the constructor says that it can read image data from a stream if you pipe it into the sharp object. "JPEG, PNG, WebP, GIF, SVG, TIFF or raw pixel image data can be streamed into the object when not present."

I'm trying to pipe a readable stream from a HTTP GET from GCS into the transform, then use toFile to get the transformed image in a file. I get an error from Sharp indicating that it isn't getting the image data input properly. Here is the code which is part of the function that does this workflow.

const avatarId = this.Uuid(),
    sharp = this.Sharp({failOnError: true}),
    instream = this.GoogleCloudStorage.GET(this.GoogleCloudStorage.getName(photo.uri)),
    fileLocation = this.getTempFileLocation()

sharp.rotate().extract({left: x, top: y, width: w, height: w})
if (w > 600) {
    sharp.resize(600, 600, {fastShrinkOnLoad: false})
    w = 600
}

instream.pipe(sharp)
return sharp.jpeg().toFile(fileLocation)
.then( info => {
    console.log('editAvatar: sharp done')
    return this.GoogleCloudStorage.POST( avatarId, this.Fs.createReadStream( fileLocation ), this.getMIMEType(info) )
} )

GoogleCloudStorage.GET basically returns File.createReadStream on cloud-storage File object. I've tested this GET call in a script, it works. GoogleCloudStorage.POST uses File.createWriteStream and pipes the passed readable stream into it. Hence it needs to receive a readable stream, which is why I'm trying to write the sharp transform to file.

The error output I get:

[02/24/2018 07:41:06.892] Error -- message: Input file is missing or of an unsupported image format -- stack: Error: Input file is missing or of an unsupported image format
events.js:163
      throw er; // Unhandled 'error' event
      ^

Error: Unexpected data on Writable Stream
    at Sharp._write (/code/api/node_modules/sharp/lib/input.js:114:14)
    at doWrite (_stream_writable.js:329:12)
    at writeOrBuffer (_stream_writable.js:315:5)
    at Sharp.Writable.write (_stream_writable.js:241:11)
    at DestroyableTransform.ondata (/code/api/node_modules/readable-stream/lib/_stream_readable.js:612:20)
    at emitOne (events.js:96:13)
    at DestroyableTransform.emit (events.js:191:7)
    at addChunk (/code/api/node_modules/readable-stream/lib/_stream_readable.js:284:12)
    at readableAddChunk (/code/api/node_modules/readable-stream/lib/_stream_readable.js:271:11)
    at DestroyableTransform.Readable.push (/code/api/node_modules/readable-stream/lib/_stream_readable.js:238:10)

Update: I experimented using File.download instead, and that works. So either I'm missing something with piping the stream into sharp, or sharp has a bug.


Solution

  • you might find this sample from Google useful, it uses sharp to thumbnail an image and put it in a bucket

    https://github.com/firebase/functions-samples/blob/69b829af5494e7c8104f7f3d10a1496bb773d3e2/image-sharp/functions/index.js