-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.js
166 lines (133 loc) · 4.13 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Based on:
// http://stackoverflow.com/questions/30876345/in-amazon-lambda-resizing-multiple-thumbnail-sizes-in-parallel-async-throws-err
// dependencies
var async = require('async');
var AWS = require('aws-sdk');
var gm = require('gm')
.subClass({
imageMagick: true
}); // Enable ImageMagick integration.
var util = require('util');
// constants
var SIZES = ['full', 100, 320, 640, 768, 960, 1024, 1440];
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;
var srcKey = event.Records[0].s3.object.key;
var region = event.Records[0].awsRegion;
var dstBucket = srcBucket;
// get reference to S3 client
var s3 = new AWS.S3({
region: region
});
console.log('S3 configured with endpoint ' + s3.endpoint.href);
// Infer the image type.
var typeMatch = srcKey.match(/\.([^.]*)$/);
if (!typeMatch) {
console.error('unable to infer image type for key ' + srcKey);
return context.done();
}
var imageType = typeMatch[1];
if (imageType != "jpg" && imageType != "jpeg" && imageType != "png") {
console.log('skipping non-image ' + srcKey);
return context.done();
}
// Download the image from S3
s3.getObject({
Bucket: srcBucket,
Key: srcKey
},
function(err, response) {
if (err)
return console.error('unable to download image ' + err);
var contentType = response.ContentType;
var original = gm(response.Body);
original.size(function(err, size) {
if (err)
return console.error(err);
//transform, and upload to a different S3 bucket.
async.each(SIZES,
function(max_size, callback) {
resize_photo(size, max_size, imageType, original, srcKey, dstBucket, contentType, s3, callback);
},
function(err) {
if (err) {
console.error(
'Unable to resize ' + srcBucket +
' due to an error: ' + err
);
} else {
console.log(
'Successfully resized ' + srcBucket
);
}
context.done();
});
});
});
};
//wrap up variables into an options object
var resize_photo = function(size, max_size, imageType, original, srcKey, dstBucket, contentType, s3, done) {
var parts = srcKey.split("/");
var filename = parts[parts.length - 1];
var dstKey = "public/" + max_size + "/" + filename;
console.log("Creating version " + dstKey);
// transform, and upload to a different S3 bucket.
async.waterfall([
function transform(next) {
if (max_size == 'full') {
original.toBuffer(imageType, function(err, buffer) {
next(null, buffer);
});
return;
}
// Infer the scaling factor to avoid stretching the image unnaturally.
// We use Math.max because we want to fill the smallest side
var scalingFactor = Math.max(
max_size / size.width,
max_size / size.height
);
// No need to waste resources upscaling.
if (scalingFactor > 1) {
original.toBuffer(imageType, function(err, buffer) {
next(null, buffer);
});
return;
}
var width = scalingFactor * size.width;
var height = scalingFactor * size.height;
// Transform the image buffer in memory.
original.resize(width, height)
.toBuffer(imageType, function(err, buffer) {
if (err) {
next(err);
} else {
next(null, buffer);
}
});
},
function upload(data, next) {
// Stream the transformed image to a different S3 bucket.
s3.putObject({
Bucket: dstBucket,
Key: dstKey,
Body: data,
ContentType: contentType
},
next);
}
], function(err) {
console.log('finished resizing ' + dstBucket + '/' + dstKey);
if (err) {
console.error(err);
} else {
console.log(
'Successfully resized ' + dstKey
);
}
done(err);
});
};