iTranslated by AI
Image Resizing on S3 Upload with AWS Lambda (Python)
AWS is so convenient, isn't it?
I have very little experience with it, but I've been using it lately out of necessity. One of the things I struggled with was the image resizing process using Lambda, as mentioned in the title.
The code is written in Python, but since it's not my specialty, I'm creating this article partly as a memo. Therefore, there are no detailed explanations. Please be aware of this in advance.
S3 Folder Structure
In this development environment, the S3 folder structure is as follows.
I'm simply storing images and other files under bucket/contents.
/bucket-name/
┗ contents
├ abc.jpg
├ xyz.png
┗ movie.mp4
...
Specifications
The specifications for executing the resizing process in Lambda are as follows:
When an image is uploaded under contents/, resize and duplicate the image into M and S sizes, adding "-m" and "-s" to the end of the filenames respectively (maintaining the aspect ratio). Then, store the resized images in the same contents/ folder as the original image.
It's not a particularly complicated specification. This time, I've set "M size: 600px, S size: 240px". Let's take a look at the code right away.
Lambda Function
import boto3
import os
from PIL import Image
import io
s3_client = boto3.client('s3')
def resize_image(image_bytes, width):
# Open image with PIL
image = Image.open(io.BytesIO(image_bytes))
# Calculate aspect ratio
aspect_ratio = image.height / image.width
new_height = int(width * aspect_ratio)
# Execute resizing
resized_image = image.resize((width, new_height), Image.Resampling.LANCZOS)
# Save to buffer
buffer = io.BytesIO()
# Maintain original format
format = image.format if image.format else 'JPEG'
resized_image.save(buffer, format=format, quality=85)
buffer.seek(0)
return buffer.getvalue()
def lambda_handler(event, context):
try:
# Get information from S3 event
bucket = event['Records'][0]['s3']['bucket']['name']
key = event['Records'][0]['s3']['object']['key']
# Process only images in the contents folder
if not key.startswith('contents/'):
return {
'statusCode': 200,
'body': 'Skipped: Not a target image'
}
# Skip already resized images
if '-m.' in key or '-s.' in key:
return {
'statusCode': 200,
'body': 'Skipped: Already resized image'
}
# Check for target extensions
if not key.lower().endswith(('.jpg', '.jpeg', '.png', '.webp')):
return {
'statusCode': 200,
'body': 'Skipped: Not a supported image format'
}
# Get the original image
response = s3_client.get_object(Bucket=bucket, Key=key)
image_bytes = response['Body'].read()
# Separate filename and path
directory = os.path.dirname(key)
filename = os.path.basename(key)
name, ext = os.path.splitext(filename)
# Create M size (600px)
m_image = resize_image(image_bytes, 600)
m_filename = f"{name}-m{ext}"
m_key = f"{directory}/{m_filename}"
s3_client.put_object(
Bucket=bucket,
Key=m_key,
Body=m_image,
ContentType=response['ContentType']
)
# Create S size (240px)
s_image = resize_image(image_bytes, 240)
s_filename = f"{name}-s{ext}"
s_key = f"{directory}/{s_filename}"
s3_client.put_object(
Bucket=bucket,
Key=s_key,
Body=s_image,
ContentType=response['ContentType']
)
return {
'statusCode': 200,
'body': 'Successfully resized image'
}
except Exception as e:
print(f'Error: {str(e)}')
raise e
The image processing library used is "Pillow".
Actually, I am not very familiar with Python, so I just had claude.ai generate the above code and tuned it. Therefore, I will skip the explanation.
Other Lambda settings are as follows.
Settings tab → General settings
- Function name: ImageResize (anything is fine)
- Memory: 512MB
- Ephemeral storage: 512MB
- Timeout: 0 min 30 sec
S3 Settings
Settings are required to send event notifications from S3 to Lambda and execute the function.
In this case, we will configure it to send an event notification to Lambda and execute the above function "when an object is created (uploaded) in contents/".
Properties
Select the bucket and choose the "Properties" tab. On the next screen, click "Create event notification" in the "Event notifications" section to add an event.

Event notifications section
Configure the settings on the next screen as follows.
General configuration
- Event name: image-resit-trigger-jpg (anything is fine)
- Prefix: contents/
- Suffix: .jpg (the file extension you want to target for resizing)
Event types
- Object creation: All object creation events
Destination
- Lambda function
- Choose from your Lambda functions (select the target function from the dropdown)
That's it for the configuration.
Now, if you actually upload an image to the S3 contents/ folder, a resized image will be generated automatically.
Below is a screenshot when "resize-test.jpg" was uploaded as a test.
You can see that "resize-test-m.jpg" and "resize-test-s.jpg" have been correctly generated.

That's all for this article. It was a rough and quick explanation, but I hope this article is helpful to someone.
Discussion