I really wanted a way to create resized images on the fly just by specifying the size of the image in the request URL. So, if I had the image kitty.jpg
but wanted to resize it to be 100px by 100px, would simply request kitty-100x100.jpg
, the server would realize it doesn't exists and create it, and the resized image would be returned to me.
I was following this guide written by John Pignata. It is an interesting solution and fit my needs but I did run into some caveats. Below are some of the gotchas I encountered.
my-bucket.s3.amazonaws.com
my-bucket.s3-website-us-west-2.amazonaws.com
The first is what CloudFront shows as a dropdown value when you're creating an origin. The second is what you ACTUALLY want if you are trying to do redirects. The second you will find at the top of the dialog box when you setup S3 static website hosting. What seems to be happening is the first domain is a "vanilla" S3 and the second is an S3 website with additional functionality (like redirects... which we need).
When I finished my implementation, I found my initial redirect was being cached. This caused my browser to keep hitting the resize lambda... not good. To remedy this, I had to set the Default TTL
for my CloudFront Origin to 0 and specify a CacheControl
value when uploading my resized image to S3. Although it's not ideal, it works for me because I have a CloudFront Origin that is only for handling images and the only images available are the resized ones; otherwise, setting a default cache of 0 would not be a good idea.
In your lambda, make sure you do a Math.floor()
(or round
or ceil
). I took this a step further and implemented the scaling factor technique shown in this article. This allowed me to force images to only scale down and have a max width/height:
const MAX_HEIGHT = 4472;
const MAX_WIDTH = 4472;
//...
var scalingFactor = Math.min(
(desired_width || MAX_WIDTH) / metadata.width,
(desired_height || MAX_HEIGHT) / metadata.height,
1 // don't scale up
);
let width = Math.floor(scalingFactor * metadata.width);
let height = Math.floor(scalingFactor * metadata.height);