• Home
  • /
  • Articles
  • /
  • Dynamic Resizing of Images for Different Resolutions: AWS Lambda + S3

Dynamic Resizing of Images for Different Resolutions: AWS Lambda + S3

All of our web and mobile apps make heavy use of images through banners, sliders, grid & feed views etc. We need to optimize the rendering of these images based on the interface a customer uses to interact with our service. For example it makes sense to serve an image in 500 x 500 pixels on devices with higher screen resolutions like laptops & desktops, but it would not make sense to render the same dimensions on our mobile websites or native apps. It would be a waste of bandwidth and lead to higher load times for users. It is standard practise to load different resolutions of the same image based on the requesting interface.

While there are many approaches to solve this common use case, in this post I will cover how we can achieve dynamic resizing of images using Amazon’s S3 and Lambda. I have recently implemented this solution in Selfie Challenge, a new product that we just release in beta for both iOS and Android platforms.

In short here is how the solution works:



When a user uploads a new pic through the app it gets stored on our AWS S3 bucket. Note that these images are usually heavy resolution selfies so quite large in size.


Within our app when a request is made to any listing page, like the one above we dynamically create a new image in 100 x 100 pixels on the home page and 500 x 500 pixels on the category listing page

This is only a one time process. Subsequent requests will directly serve this image so latency will be not affected. Our original high resolution image is only needed when someone clicks on an image to view it in full screen mode.

Solution implementation and request flow can be depicted as follows:

Step by step instructions to implement dynamic image resizing with AWS:

  • Login to AWS management console with an account that has enough permissions to modify and create resources on S3, Lambda and API Gateway.
  • Create an S3 bucket and dump all your high resolution images in it. Let’s say the name of my S3 bucket is “com.mywebsite.images”.
  • Go to the permissions tab -> Bucket Policy and add the following rule.

  • Go back to Properties tab, select Static Website Hosting and enable hosting. Also enter index.html as the starting point. Copy and keep a note of the hostname created for your static website. For example it was http://com.mywebsite.images.s3-website.ap-south-1.amazonaws.com for me.

  • Create a new AWS Lambda function by selecting the “Author from Scratch” blueprint and give it a relevant name like “resizeForSelfie” in my case. My lambda function will run Node so the default selection below is fine.

  • We need to define the execution role permissions for our Lambda function. To do this we will create a new custom role, so select that from the dropdown.

  • In the new tab that opens up, select lambda_basic_execution as the IAM role, select “Create a new Role Policy” from the Policy Name dropdown and click edit and paste the below policy. Do remember to change the name of your bucket accordingly.

  • Next we need to add an API Gateway trigger to our Lambda function which will invoke our function through an HTTP request. Configure the trigger by providing an appropriate API name (could be anything relevant), select deployment stage  as “prod” and Security as “open” since we want to invoke this function over HTTP without any additional credentials.

  • Finally we will upload the actual code for the Lambda function. Amazon has a ready made code base available for this which you can download from here. Select “Upload a .zip file” from Code Entry type and upload the file we just downloaded.

  • A couple of environment variables need to be initialised for our Lambda function to work correctly. So set the following:
    • BUCKET -> name of your bucket, in my case com.mywebsite.images
    • URL -> The static website hosting URL we copied earlier. In my case this is http://com.mywebsite.images.s3-website.ap-south-1.amazonaws.com

  • Also, allocate around 1536 MB for Memory and set the timeout value to around 10 secs. This is recommended by AWS for this example. Go ahead and save your function.
  • Now browse to the Triggers section to reveal your API Gateway endpoint which will invoke our Lambda function. Copy and note this endpoint.

  • Go back to the S3 bucket console, expand Static Website Hosting -> Edit Redirection Rules and paste the following rule.

 

 

 

Note that you need to enter only the hostname part of your API Gateway endpoint on line 9 above and the exact name of our function on line 10 (resizeForSelfie in this example).

That’s it! We are done. Now we should be able to dynamically resize any image from our S3 bucket and serve it immediately.

Say we have image named “abc.jpg” at the root level in our S3 bucket above.

  • To access the full resolution image we can open up:
    • http://com.mywebsite.images.s3-website.ap-south-1.amazonaws.com/abc.jpg
  • To access a 300 x 300 px version of this image we can call:
    • http://com.mywebsite.images.s3-website.ap-south-1.amazonaws.com/300×300/abc.jpg
  • To access a 100 x 200 px version of the original image we call:
    • http://com.mywebsite.images.s3-website.ap-south-1.amazonaws.com/100×200/abc.jpg

 

 

P.S. I wrote this article after following the step by step instructions provided by AWS here. While the original article is spot on, I had some trouble actually implementing it on my project due to some really silly errors on my part and changes in AWS console interfaces and documentation. That’s the reason I have added screenshots and illustrations to help me not make the same mistakes again in the future 🙂 Happy coding!

 

9 Comments

  • Joshy Mathew

    July 16, 2018 at 10:50 pm

    Thank you for the great tutorial.
    I have a questions for you.
    While I am accessing the 300×300 px version of the image I am getting
    {“message”:”Forbidden”}
    response. Why this is happening. Do I need to change any configurations ?

    Reply
    • Adil Shaikh

      October 8, 2018 at 12:44 am

      hi Joshy, this just means that you have granted public permissions to your S3 bucket. Go into your S3 bucket settings and make the entire folder public.. That should fix it.

      Reply
  • Rishabh Shukla

    October 7, 2018 at 10:21 pm

    Hi Adil,
    Thanks for the great post. I implemented the whole structure on my end and its working very smoothly. The only issue i have right now is maintaining the aspect ratio. As you know S3 doesn’t store the dimensions of the images in the bucket. And since i have no way of maintaining the aspect ratio with the dimensions, the image gets cropped when an disproportionate aspect ratio is given as the input. I tried playing around with the lambda function code too in the resize part by removing the height or passing height as null, but i kept getting errors in every attempt. Do you think you can help me out here?

    Reply
    • Adil Shaikh

      October 8, 2018 at 12:43 am

      sure Rishabh, let me check on how we can maintain the aspect ratio when generating the new image. Will revert by tomorrow maybe as I am caught up with a few work items.

      Reply
      • Rishabh Shukla

        October 9, 2018 at 3:51 am

        Hi Adil,
        I figured it out.
        Basically all i did was replace the height from inside the zip function with null while resizing and it autoscales the output image.

        Reply
        • Adil Shaikh

          October 9, 2018 at 4:03 am

          Thats fantastic Rishabh! I think it would be helpful for me as well since maintaining aspect size is super important even while generating thumbnails to avoid distortions. Thanks for sharing this info, will be helpful for me and other readers as well. Cheers!

          Reply

Leave a Reply