This is a simple image resizer for image download via CloudFront. It is implemented as a Lambda@Edge function. Specifically, this Lambda@Edge function is triggered by the Origin Request
and Origin Response
events. When the function is triggered, it checks the requested image size and resizes the image to the requested size. The resized image is then returned to the user.
For backward compatibility, the Lambda function is triggered by the Origin Request
event for some specific cases. If the requested URI is like /path/to/file_L.jpg
, the postfix of the file name _L
is used to resize the image. Let's call the postfix as resizing hint. There are four types of resizing hints:
_t
wants to resize the image width to 100 px_s
wants to resize the image width to 200 px_m
wants to resize the image width to 300 px_l
wants to resize the image width to 400 px
The specific width of each postfix should be rechecked and updated if necessary.
After parsing the resizing hint from the requested URI, the Lambda function modifies the URI without the resizing hint and adjust query string to have the matched width. w
parameter in query string is the requested width for resizing.
This could be achieved by triggering the Lambda function by the Viewer Request
event. This would be more efficient in terms of cache hit ratio in CloudFront. But, the Lambda function platform for Viewer Request
event is restricted only to Javascript, and the function will be executed for all image requests, which means higher cost. As a trade-off, the Lambda function triggered by Origin Request
might have lower cache hit ratio, but the execution count would be much less. As a result, I chose to process this business logic in Origin Request
event stage.
From the request via CloudFront, there are some parameters that are used to resize the image. The parameters are as follows:
- S3 bucket name set in CloudFront distribution
- Path of an object in S3 bucket
- Requested image size (width and height) in the query string
- width:
w
(default is None) - height:
h
(default is None)
- width:
- Requested quality of the image in the query string
- quality:
q
(default is 80)
- quality:
After parsing the parameters from the request, the Lambda function loads the image object from S3 bucket. From the object, the function reads the image data as follows:
- Image format from Content-Type, e.g.
image/jpeg
- Image data as BytesIO stream
After that, the Lambda function resizes the image to the requested size. Here are specific rules for resizing the image:
- If width and height are both specified, the image is resized to the requested size
- The maximum width is 2000 px and the maximum height is 5000 px defined in
image.py
- The maximum width is 2000 px and the maximum height is 5000 px defined in
- If width is specified but not height, the image is resized to the requested width keeping the aspect ratio
- But, if the requested width is larger than the original width, the image is returned as is
- If height is specified but not width, the image is resized to the requested height keeping the aspect ratio
- But, if the requested height is larger than the original height, the image is returned as is
- If neither width nor height is specified, the image is returned as is
- If the image format is JPEG, the image is compressed to the requested quality
Basically, the image format is kept as is. Here are the supported image formats defined at ImageFormat
enum in image.py
:
- JPEG
- PNG
- GIF
- WEBP
- TIFF
If the object doesn't have the supported image format (or the object is not image), the Lambda function returns Origin Response
as is.
- Python 3.12
- Poetry
brew install [email protected]
brew install poetry
# Install dependencies manually via Poetry
# or open the project in Pycharm and let it install the dependencies
poetry install
pytest --cov
Should be automated in the future, but for now, it is a manual process.
- Create
artifact.zip
file in thedeploy
directory by running./build.sh
- Upload the
artifact.zip
file to the Lambda function in the AWS console - Deploy the Lambda function as a Lambda@Edge function
- https://aws.amazon.com/blogs/networking-and-content-delivery/resizing-images-with-amazon-cloudfront-lambdaedge-aws-cdn-blog
- https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-at-edge-function-restrictions.html
- https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/edge-functions-choosing.html
- https://github.com/healingpaper-solution/image-resizer-lambda
- https://github.dev/hoony9x/aws-lambda-edge-img-resize-function
- https://taxijjang.tistory.com/185
- https://velog.io/@kpl5672/python-pillow-resize-thumbnail-%EC%82%AC%EC%9A%A9-%EC%8B%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-rotate%EB%90%98%EB%8A%94-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0
- https://stackoverflow.com/questions/50963537/pil-make-image-transparent-on-a-percent-scale