|
| 1 | +const gm = require('gm').subClass({ imageMagick: false }); |
| 2 | +const AWS = require('aws-sdk'); |
| 3 | + |
| 4 | +const s3 = new AWS.S3(); |
| 5 | + |
| 6 | +exports.handler = async (event, context, cb) => { |
| 7 | + const validExtensions = ['jpg', 'jpeg', 'png']; |
| 8 | + |
| 9 | + const { bucket, object } = event.Records[0].s3; |
| 10 | + |
| 11 | + // Where images are uploaded |
| 12 | + const origin = 'original/'; |
| 13 | + |
| 14 | + // Where optimized images will be saved |
| 15 | + const dest = 'thumbs/'; |
| 16 | + |
| 17 | + // Object key may have spaces or unicode non-ASCII characters. Remove prefix |
| 18 | + const fullFileName = decodeURIComponent(object.key.replace(/\+/g, ' ')) |
| 19 | + .split('/').pop(); |
| 20 | + |
| 21 | + const [fileName, fileExt] = fullFileName.split('.'); |
| 22 | + |
| 23 | + if (!validExtensions.includes(fileExt)) { |
| 24 | + return cb(null, `Image not processed due to .${fileExt} file extension`); |
| 25 | + } |
| 26 | + |
| 27 | + // Download image from S3 |
| 28 | + const s3Image = await s3. |
| 29 | + getObject({ |
| 30 | + Bucket: bucket.name, |
| 31 | + Key: `${origin}${fullFileName}` |
| 32 | + }) |
| 33 | + .promise(); |
| 34 | + |
| 35 | + function gmToBuffer(data) { |
| 36 | + return new Promise((resolve, reject) => { |
| 37 | + data.stream((err, stdout, stderr) => { |
| 38 | + if (err) { return reject(err) } |
| 39 | + const chunks = [] |
| 40 | + stdout.on('data', (chunk) => { chunks.push(chunk) }) |
| 41 | + stdout.once('end', () => { resolve(Buffer.concat(chunks)) }) |
| 42 | + stderr.once('data', (data) => { reject(String(data)) }) |
| 43 | + }) |
| 44 | + }) |
| 45 | + } |
| 46 | + |
| 47 | + function getBuffer(body, size, quality) { |
| 48 | + const data = gm(body) |
| 49 | + .resize(size) |
| 50 | + .quality(quality); |
| 51 | + |
| 52 | + return gmToBuffer(data); |
| 53 | + } |
| 54 | + |
| 55 | + // use null to optimize image without resizing |
| 56 | + const sizes = [null, 1200, 640, 420]; |
| 57 | + |
| 58 | + // Uploades all images to S3 |
| 59 | + const uploadPromises = sizes.map(async size => { |
| 60 | + // Optimize image with current size |
| 61 | + const imgBuffer = await getBuffer(s3Image.Body, size, 60); |
| 62 | + const key = size |
| 63 | + ? `${dest}${fileName}_thumb_${size}.${fileExt}` |
| 64 | + : `${dest}${fileName}_original.${fileExt}`; |
| 65 | + |
| 66 | + return s3.putObject({ |
| 67 | + Bucket: bucket.name, |
| 68 | + Key: key, |
| 69 | + Body: imgBuffer, |
| 70 | + }).promise(); |
| 71 | + }); |
| 72 | + |
| 73 | + await Promise.all(uploadPromises); |
| 74 | + |
| 75 | + cb(null, 'finished'); |
| 76 | +}; |
| 77 | + |
| 78 | +if (process.env.LOCAL === 'true') { |
| 79 | + exports.handler(require('./event.json'), null, (err, res) => { |
| 80 | + console.log(res); |
| 81 | + }); |
| 82 | +} |
0 commit comments