-
-
Save SHohentanner/d615a23784ef692ebec35f681a5f49d3 to your computer and use it in GitHub Desktop.
AWS Lambda Thumbnailer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var async = require("async"); | |
var AWS = require("aws-sdk"); | |
var gm = require("gm").subClass({imageMagick: true}); | |
var fs = require("fs"); | |
var mktemp = require("mktemp"); | |
var THUMB_KEY_PREFIX = "thumbnails/", | |
THUMB_WIDTH = 150, | |
THUMB_HEIGHT = 150, | |
ALLOWED_FILETYPES = ['png', 'jpg', 'jpeg', 'bmp', 'tiff', 'pdf', 'gif']; | |
var utils = { | |
decodeKey: function(key) { | |
return decodeURIComponent(key).replace(/\+/g, ' '); | |
} | |
}; | |
var s3 = new AWS.S3(); | |
exports.handler = function(event, context) { | |
var bucket = event.Records[0].s3.bucket.name, | |
srcKey = utils.decodeKey(event.Records[0].s3.object.key), | |
dstKey = THUMB_KEY_PREFIX + srcKey.replace(/\.\w+$/, ".png"), | |
fileType = srcKey.match(/\.\w+$/); | |
if(srcKey.indexOf(THUMB_KEY_PREFIX) === 0) { | |
return; | |
} | |
if (fileType === null) { | |
console.error("Invalid filetype found for key: " + srcKey); | |
return; | |
} | |
fileType = fileType[0].substr(1); | |
if (ALLOWED_FILETYPES.indexOf(fileType) === -1) { | |
console.error("Filetype " + fileType + " not valid for thumbnail, exiting"); | |
return; | |
} | |
async.waterfall([ | |
function download(next) { | |
//Download the image from S3 | |
s3.getObject({ | |
Bucket: bucket, | |
Key: srcKey | |
}, next); | |
}, | |
function createThumbnail(response, next) { | |
var temp_file, image; | |
if(fileType === "pdf") { | |
temp_file = mktemp.createFileSync("/tmp/XXXXXXXXXX.pdf") | |
fs.writeFileSync(temp_file, response.Body); | |
image = gm(temp_file + "[0]"); | |
} else if (fileType === 'gif') { | |
temp_file = mktemp.createFileSync("/tmp/XXXXXXXXXX.gif") | |
fs.writeFileSync(temp_file, response.Body); | |
image = gm(temp_file + "[0]"); | |
} else { | |
image = gm(response.Body); | |
} | |
image.size(function(err, size) { | |
/* | |
* scalingFactor should be calculated to fit either the width or the height | |
* within 150x150 optimally, keeping the aspect ratio. Additionally, if the image | |
* is smaller than 150px in both dimensions, keep the original image size and just | |
* convert to png for the thumbnail's display | |
*/ | |
var scalingFactor = Math.min(1, THUMB_WIDTH / size.width, THUMB_HEIGHT / size.height), | |
width = scalingFactor * size.width, | |
height = scalingFactor * size.height; | |
this.resize(width, height) | |
.toBuffer("png", function(err, buffer) { | |
if(temp_file) { | |
fs.unlinkSync(temp_file); | |
} | |
if (err) { | |
next(err); | |
} else { | |
next(null, response.contentType, buffer); | |
} | |
}); | |
}); | |
}, | |
function uploadThumbnail(contentType, data, next) { | |
s3.putObject({ | |
Bucket: bucket, | |
Key: dstKey, | |
Body: data, | |
ContentType: "image/png", | |
ACL: 'public-read', | |
Metadata: { | |
thumbnail: 'TRUE' | |
} | |
}, next); | |
} | |
], | |
function(err) { | |
if (err) { | |
console.error( | |
"Unable to generate thumbnail for '" + bucket + "/" + srcKey + "'" + | |
" due to error: " + err | |
); | |
} else { | |
console.log("Created thumbnail for '" + bucket + "/" + srcKey + "'"); | |
} | |
context.done(); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @oguzhancagliyan
I plan on updating it at some point but not right now. Did you find a solution? If so, please let me know.
Best,
Simon