2

I am trying to write a Lambda function that takes an image stored as an S3 object, reads its height and width, and moves it to a different prefix in the same bucket. Then, it takes the image and resizes it while keeping the original aspect ratio, and writes the resized image to the original prefix of the object.

My code is based on the example here. I'm completely new to NodeJS and JS in general.

To achieve what I want, I have set up two different pipelines. Both are composed of 3 streams. The first pipeline has a read stream, a stream that gets the metadata, and a write stream. The second pipeline is read, resize, write.

I am not sure how to properly read the metadata of the image off the stream. The whole code is here. I'll try to include only relevant snippets in the question.

This function is meant to be used as part of the pipeline. It is meant to read the height and width of the image and store them in variables.

// Get size from stream (sharp)
const getSizeFromStream = () => {
    const pass = new stream.PassThrough();
    const metadata = sharp(pass).metadata().then(metadata =>
        {
            return {
                writeStream: pass,
                width: metadata.width,
                height: metadata.height
            };

        });
};

This gets called through a pipeline:

            const readStreamOrig = readStreamFromS3(params);

            const {
                passThroughStream,
                origWidth,
                origHeight
            } = getSizeFromStream();

            const {
                writeStreamOrig,
                uploadFinishedOrig
            } = writeStreamToS3({Bucket: params[0], Key: newKey});

            readStreamOrig
                .pipe(passThroughStream)
                .pipe(writeStreamOrig);

where the read and write stream interact with the S3 object that trigerred the Lambda function.

However, this doesn't work, yielding these two errors:

{
    "errorType": "TypeError",
    "errorMessage": "Cannot destructure property `passThroughStream` of 'undefined' or 'null'."
}
{
    "errorType": "Runtime.UnhandledPromiseRejection",
    "errorMessage": "Error: Input file is missing or of an unsupported image format",
}

I am not exactly sure how streams get passed to streams, and how to access them from functions. I'm not also not sure if assigning variables from a stream like this makes sense. How should I write the function that reads the metadata?

Rob
  • 14,746
  • 28
  • 47
  • 65
Joey Dumont
  • 898
  • 2
  • 7
  • 25

1 Answers1

0

I'd think of it more of :
- Move the image on S3 from it's name to it's name with the prefix
- Read the stream from the prefixed image, use sharp pipe to resize the image/do transformations, write back to S3 stream to un-prefixed image

Example of the sharp stream:

// Before this, use S3 API to move the image to its prefixed name
// Then...

const readStream = readStreamFromS3(params); // Read prefixed image from S3

const resizeStream = sharp()
  .resize(200, 200)
  .png();

const s3WriteStream = writeStreamToS3({
  Bucket: unprefixedBucket,
  Key: unprefixedKey,
});

readStream
  .pipe(resizeStream)
  .pipe(s3WriteStream);

Or did I get it wrong and you actually want to extract the width and height from the image also?

yachaka
  • 5,429
  • 1
  • 23
  • 35