Created
August 11, 2023 19:05
-
-
Save Saigesp/33023f3252cc99a87352cc5493a9531a to your computer and use it in GitHub Desktop.
Python responsive images
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# Create multiple responsive images to generate a srcset | |
# | |
# Usage example: | |
# b64_image = base64.b64decode(b64_image.split(",")[1]) # from base64-encoded image | |
# file_name = "lorem.ipsum.jpeg" | |
# srcset_results = [] | |
# for img in create_srcset_images(BytesIO(b64_image), widths): | |
# srcset_name = f'{".".join(file_name.split(".")[:-1])}-{img["width"]}w.{img["format"]}' | |
# result = upload_file_to_external_service(img["image"], srcset_name) # <--- it must return a URL | |
# srcset_results.append(f'{result} {img["width"]}w') | |
# srcset = ", ".join(srcset_results) | |
# | |
# Code adapted from https://github.com/mccarthysean/make-responsive-images/ | |
from io import BytesIO | |
from PIL import Image | |
def get_srcset_sizes(widths: list, img_width: int, img_height: int) -> list: | |
""" | |
Get srcset proporcional sizes and filter out duplicates sizes | |
and larger than original | |
:param widths: list of widths to to create the srcset | |
:param img_width: image original width | |
:param img_height: image original height | |
:return: list of proportinal sizes like [(400, 267), (800, 533), (1200, 800)] | |
""" | |
sizes_set = set() | |
for width in widths: | |
width = min(width, img_width) | |
ratio = width / float(img_width) | |
width = int(img_width * ratio + 0.5) | |
height = int(img_height * ratio + 0.5) | |
sizes_set.add((width, height)) | |
return sorted(sizes_set) | |
def create_srcset_images( | |
file: BytesIO, | |
widths: list = [1200, 800, 600, 400], | |
output_format: str = "webp", | |
output_quality: int = 100, | |
resize_method: int = Image.NEAREST, | |
) -> list: | |
""" | |
Resize the image to the widths specified | |
:param file: file to resize | |
:param output_format: output files format. Can be jpg or webp | |
:param output_quality: compression files output_quality | |
:param resize_method: resize method. Can be Image.NEAREST or Image.ANTIALIAS | |
:return: list of dicts that contain images with their sizes | |
""" | |
output_format = output_format.lower() | |
if output_format not in ("jpg", "webp", "png"): | |
raise TypeError('output_format must be either "jpg", "webp" or "png"') | |
if output_quality > 100 or output_quality < 0: | |
raise TypeError("output_quality must be between 0 and 100") | |
image = Image.open(file).convert("RGB") # Convert to RGB so we can save as .webp | |
sizes = get_srcset_sizes(widths, image.width, image.height) | |
result = [] | |
for (width, height) in sizes: | |
if (width, height) == (image.width, image.height): | |
new_image = image | |
else: | |
new_image = image.resize((width, height), resize_method) | |
in_mem_file = BytesIO() | |
new_image.save(in_mem_file, quality=output_quality, format=output_format) | |
in_mem_file.seek(0) | |
result.append( | |
{ | |
"image": in_mem_file, | |
"width": width, | |
"height": height, | |
"format": output_format, | |
} | |
) | |
return result |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment