Skip to content

Instantly share code, notes, and snippets.

@kennyhyun
Created September 6, 2016 02:04
Show Gist options
  • Save kennyhyun/6ec6e6c75a4d1913c8fadfbc93fdf42e to your computer and use it in GitHub Desktop.
Save kennyhyun/6ec6e6c75a4d1913c8fadfbc93fdf42e to your computer and use it in GitHub Desktop.
Lamda function to convert pdf to png and generate thumbnails for images.

Lambda environment includes gm package by default. it is actually dependant to ghost script. so I checked it in Amazon Linux and could find the binary in /usr/bin/. and tried it in Lambda and it worked. This is using /usr/bin/gs which there was already in Lambda environment. so I think there is no need to build ghostscript binary. (at least for a while)

// dependencies
var async = require('async');
var AWS = require('aws-sdk');
// Enable ImageMagick integration.
var gm = require('gm').subClass({ imageMagick: true });
var util = require('util');
var pdf2png = require('pdf2png');
pdf2png.ghostscriptPath = "/usr/bin";
// constants
var MAX_WIDTH = 320;
var MAX_HEIGHT = 320;
// get reference to S3 client
var s3 = new AWS.S3();
exports.handler = function(event, context) {
// Read options from the event.
console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
var srcBucket = event.Records[0].s3.bucket.name;
// Object key may have spaces or unicode non-ASCII characters.
var srcKey =
decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
var isTest = srcBucket.indexOf('-test') >= 0;
var dstBucket = srcBucket.split('-')[0];
dstBucket += "-thumbnails";
if (isTest) {
dstBucket += '-test';
}
var dstKey = srcKey;
// Sanity check: validate that source and destination are different buckets.
if (srcBucket == dstBucket) {
console.error("Destination bucket must not match source bucket.");
return;
}
// Infer the image type.
var typeMatch = srcKey.match(/\.([^.]*)$/);
if (!typeMatch) {
console.error('unable to infer image type for key ' + srcKey);
return;
}
var imageType = typeMatch[1].toLowerCase();
if (imageType != "jpg" && imageType != "png" && imageType != "pdf") {
console.log('skipping non-image ' + srcKey);
return;
}
// Download the image from S3, transform, and upload to a different S3 bucket.
async.waterfall([
function download(next) {
// Download the image from S3 into a buffer.
s3.getObject({
Bucket: srcBucket,
Key: srcKey
},
next);
},
function transform(response, next) {
if (imageType == "pdf") {
pdf2png.convert(response.Body, function(resp) {
if (!resp.success) {
next(resp.error);
return;
}
next(null, "image/png", resp.data);
});
} else {
gm(response.Body).size(function(err, size) {
// Infer the scaling factor to avoid stretching the image unnaturally.
var scalingFactor = Math.min(
MAX_WIDTH / size.width,
MAX_HEIGHT / size.height
);
var width = scalingFactor * size.width;
var height = scalingFactor * size.height;
// Transform the image buffer in memory.
this.resize(width, height)
.toBuffer(imageType, function(err, buffer) {
if (err) {
next(err);
} else {
next(null, response.ContentType, buffer);
}
});
});
}
},
function upload(contentType, data, next) {
// Stream the transformed image to a different S3 bucket.
var ext = '';
if (imageType == "pdf") {
ext = '.png';
dstBucket = srcBucket;
}
s3.putObject({
Bucket: dstBucket,
Key: dstKey + ext,
Body: data,
ContentType: contentType,
ACL:'public-read'
},
next);
}
], function (err) {
if (err) {
console.error(
'Unable to resize ' + srcBucket + '/' + srcKey +
' and upload to ' + dstBucket + '/' + dstKey +
' due to an error: ' + err
);
} else {
console.log(
'Successfully resized ' + srcBucket + '/' + srcKey +
' and uploaded to ' + dstBucket + '/' + dstKey
);
}
context.done();
}
);
};
@antoniohof
Copy link

gs is not longer in the new lambda runtime env from june 2019 onwards

@kennyhyun
Copy link
Author

@antoniohof Thanks for the updates! Without gs, we could 1. build our own binary in https://github.com/lambci/docker-lambda or 2. use Fargate rather than using Lambda like https://serverless.com/blog/serverless-application-for-long-running-process-fargate-lambda/
It's demanding to catch up with the latest things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment