Emmanuel Randon
Emmanuel Randon

Reputation: 101

Creating a lambda function to generate PDF file thumbnails

I have been trying to create a AWS node lambda function to download a PDF file from S3, generate a thumbnail for the first page of that file, and upload that thumbnail back to S3. Since I am no expert I tried inspiring myself from the Lambda example provide by AWS to resize images as well as a node.js found on SO of a PDF thumbnail generator in node.js but have not been able to make it work. The download from S3 works, the upload back to S3 works, but the thumbnail generation fails. See my code below:

// Download the pdf from S3, create thumbnail, and upload to cache.
	async.waterfall([
		function download(next) {
			// Download the pdf from S3 into a buffer.
			s3.getObject({
					Bucket: BUCKET,
					Key: pdfkey
				},
				next);
			},
		function thumbnail(response, next) {
			gm(response.Body[0]).size(function(err, size) {
				// Transform the image buffer in memory.
				this.resize(requestedwidth, requestedheight).toBuffer(format.toUpperCase(), function(err, buffer) {
					if (err) {
						console.log('failed generating thumbnail');
						next(err);
					} else {
						next(null, response.ContentType, buffer);
					}
				});
			});
		},
		function upload(contentType, data, next) {
			// Stream the thumbnail
			s3.putObject({
					Bucket: BUCKET,
					Key: thumbnailkey,
					ACL:"public-read",
					Body: data,
					ContentType: contentType
				},
				next);
			}
		], function (err) {
			if (err) {
				context.fail(new Error(
					'Unable to create thumbnail for ' + BUCKET + '/' + pdfkey +
					' and upload to ' + BUCKET + '/' + thumbnailkey +
					' due to an error: ' + err
				));
			} else {
				context.succeed(
					'Successfully resized ' + BUCKET + '/' + pdfkey +
					' and uploaded to ' + BUCKET + '/' + thumbnailkey
				);
			}
		}
	);

Any help would be greatly appreciated!

Upvotes: 5

Views: 5672

Answers (1)

Emmanuel Randon
Emmanuel Randon

Reputation: 101

Here is the code that ended up working. Code below with the following 4 libs in node modules:

  • async
  • gm
  • mktemp
  • pdf-image

:

var async = require('async');
var AWS = require('aws-sdk');
var gm = require('gm').subClass({ imageMagick: true }); // Enable ImageMagick integration. 
var util = require('util');
var fs = require('fs');
var mktemp = require("mktemp");

var BUCKET  = "XXXXXXXXXX";

var s3 = new AWS.S3();
exports.handler = function(event, context) {

var pdfkey = decodeURIComponent(event.pdfkey.replace(/\+/g, " ")); 
var thumbnailkey = decodeURIComponent(event.thumbnailkey.replace(/\+/g, " ")); 
var requestedwidth = event.width;
var requestedheight = event.height;
var shape = event.shape;
var format = event.format;

// Infer the pdf type.
var typeMatch = pdfkey.match(/\.([^.]*)$/);
if (!typeMatch) {
    context.fail(new Error('unable to infer pdf type for key ' + pdfkey));
    return;
}
var fileType = typeMatch[1];
if (fileType != "pdf") {
    context.fail(new Error('skipping non-pdf ' + pdfkey));
    return;
}

// Download the pdf from S3, create thumbnail, and upload to cache.
async.waterfall([
    function download(next) {
        // Download the pdf from S3 into a buffer.
        s3.getObject({
            Bucket: BUCKET,
            Key: pdfkey
        },
        next);
    },
    function thumbnail(response, next) {
        console.log('generating thumbnail');
        var temp_file, image;

        temp_file = mktemp.createFileSync("/tmp/XXXXXXXXXX.pdf");
        fs.writeFileSync(temp_file, response.Body);
        image = gm(temp_file + "[0]").flatten().colorspace("CMYK");

        image.size(function(err, size) {
            if ((requestedwidth > 0) && (requestedheight > 0))
            {

                if (shape == "pad")
                {
                    // Transform the image buffer in memory.
                    this.resize(requestedwidth, requestedheight).gravity('Center').background('transparent').extent(requestedwidth, requestedheight)
                    .toBuffer(format.toUpperCase(), function(err, buffer) {
                        if (err) {
                            next(err);
                        } else {
                            next(null, response.ContentType, buffer);
                        }
                    });
                }
                else
                {
                    // Transform the image buffer in memory.
                    this.resize(requestedwidth, requestedheight)
                    .toBuffer(format.toUpperCase(), function(err, buffer) {
                        if (err) {
                            next(err);
                        } else {
                            next(null, response.ContentType, buffer);
                        }
                    });
                }
            }
            else
            {
                if (requestedwidth > 0)
                {
                    // Transform the image buffer in memory.
                    this.resize(requestedwidth)
                    .toBuffer(format.toUpperCase(), function(err, buffer) {
                        if (err) {
                            next(err);
                        } else {
                            next(null, response.ContentType, buffer);
                        }
                    });

                }
                else
                {
                    // Transform the image buffer in memory.
                    this.resize(null, requestedheight)
                    .toBuffer(format.toUpperCase(), function(err, buffer) {
                        if (err) {
                            next(err);
                        } else {
                            next(null, response.ContentType, buffer);
                        }
                    });
                }
            }
        });
    },
    function upload(contentType, data, next) {
        // Stream the thumbnail
        console.log('uploading thumbnail');
        s3.putObject({
            Bucket: BUCKET,
            Key: thumbnailkey,
            ACL:"public-read",
            Body: data,
            ContentType: "image/" + format
        },
        next);
    }
    ], function (err) {
        if (err) {
            context.fail(new Error(
                'Unable to create thumbnail for ' + BUCKET + '/' + pdfkey +
                ' and upload to ' + BUCKET + '/' + thumbnailkey +
                ' due to an error: ' + err
                ));
        } else {
            context.succeed(
                'Successfully resized ' + BUCKET + '/' + pdfkey +
                ' and uploaded to ' + BUCKET + '/' + thumbnailkey
                );
        }
    }
    );
};

Upvotes: 5

Related Questions