Build image resizer using AWS lambda-serverless framework

Manjurul Hoque Rumi
2 min readApr 29, 2023

We will build an instant image resizer using AWS lambda and S3 events. When a new image is uploaded to a specific bucket, we will catch it, resize it and re-upload it to S3.

Create the function

Create the function by the command:

sls create -t aws-python3 -p thumbnail-generator

Now, create virtualenv locally.

virtualenv venv -p python

It will create a folder named venv in your root folder. Activate the virtualenv by source venv/bin/activate. Now, install two packages called boto3 and pillow:pip install boto3 pillow

Serverless framework plugin

To use a third-party package in your functions, we need to install a plugin called serverless-python-requirements

You will see a plugins block in serverless.yml. Create a file requirements.txt and write our package's name.

Handler function

Make our function name s3_thumbnail_generator in the handler.py file.

import boto3
from io import BytesIO
from PIL import Image, ImageOps
import os

s3 = boto3.client('s3')
size = 128

def s3_thumbnail_generator(event, context):
records = event.get('Records', [])
if len(records):
bucket = records[0].get('s3', {}).get('bucket', {}).get('name')
key = records[0].get('s3', {}).get('object', {}).get('key')
# only create a thumbnail on non thumbnail pictures
if bucket and key:
# get the image
image = get_s3_image(bucket, key)
# resize the image
thumbnail = image_to_thumbnail(image)
# get the new filename
thumbnail_key = new_filename(key)
# upload the file
url = upload_to_s3(bucket, thumbnail_key, thumbnail)
return url

From the event param, we will get Records that comes from the s3 notification event. Then we extract the bucket and file name.

Here are the utils to handle image processing:

def get_s3_image(bucket, key):
print("Getting image from S3 with key: {}".format(key))
response = s3.get_object(Bucket=bucket, Key=key)
image_content = response['Body'].read()

img = Image.open(BytesIO(image_content))
return img


def image_to_thumbnail(image):
return ImageOps.fit(image, (size, size), Image.ANTIALIAS)


def new_filename(key):
key_split = key.rsplit('.', 1)
return key_split[0] + "_thumbnail.png"

We fetch the image from the bucket, convert the image to a thumbnail, then generate the filename.

To re-upload the converted image:

def upload_to_s3(bucket, key, image):
out_thumbnail = BytesIO()
image.save(out_thumbnail, 'PNG')
out_thumbnail.seek(0)

response = s3.put_object(
# ACL='public-read',
Body=out_thumbnail,
Bucket=bucket,
ContentType='image/png',
Key=key
)

url = '{}/{}/{}'.format(s3.meta.endpoint_url, bucket, key)
return url

Here is the serverless.yml:

# Welcome to Serverless!

service: thumbnail-generator

frameworkVersion: '3'

provider:
name: aws
runtime: python3.8
region: us-east-1
profile: rumi # IAM user
timeout: 10
memorySize: 128
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:*"
Resource: "*"

custom:
bucket: s3-thumbnail-generator
pythonRequirements:
dockerizePip: true

functions:
thumbnail_generator:
handler: handler.s3_thumbnail_generator
events:
- s3:
bucket: ${self:custom.bucket}
event: s3:ObjectCreated:*

plugins:
- serverless-python-requirements

Deployment

To deploy the function run the below command:
sls deploy

It will bundle the package and then deploy it to s3. You can check your buckets. Now, go to the s3 bucket and upload an image. It will generate a thumbnail instantly.

--

--