Last active
May 8, 2024 17:57
-
-
Save MarkParker5/2f08d1e9a858363273e03ea664a964f4 to your computer and use it in GitHub Desktop.
Minimize images for web: resize to max width and convert to webp
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
from PIL import Image | |
import os | |
def add_transparent_border(img: Image.Image) -> Image.Image: | |
border_size = 50 | |
new_size = (img.width + 2 * border_size, img.height + 2 * border_size) | |
new_img = Image.new('RGBA', new_size) | |
new_img.paste(img, (border_size, border_size)) | |
return new_img | |
def add_background(img: Image.Image) -> Image.Image: | |
bg_color = (28, 28, 28) | |
if img.mode != 'RGBA': | |
img = img.convert('RGBA') | |
background = Image.new('RGBA', img.size, bg_color + (255,)) | |
combined = Image.alpha_composite(background, img) | |
return combined.convert('RGB') | |
def resize_image(img: Image.Image, max_width: int) -> Image.Image: | |
if img.width > max_width: | |
scale_ratio = max_width / img.width | |
new_height = int(img.height * scale_ratio) | |
img = img.resize((max_width, new_height), Image.LANCZOS) | |
return img | |
def convert_to_webp(img: Image.Image, output_path: str) -> None: | |
img.save(output_path, 'WEBP') | |
def print_image_stats(name: str, before_size: int, after_size: int, before_dims: tuple, after_dims: tuple) -> None: | |
before_size_mb = before_size / (1024 * 1024) | |
after_size_mb = after_size / (1024 * 1024) | |
pixel_reduction = int((after_dims[0] * after_dims[1]) / (before_dims[0] * before_dims[1]) * 100) | |
print(f'\n{name}') | |
print(f'Before: {before_dims[0]}x{before_dims[1]}, {before_size_mb:.2f} MB') | |
print(f'After: {after_dims[0]}x{after_dims[1]}, {after_size_mb:.2f} MB') | |
print(f'Size reduction: {100 - pixel_reduction}%') | |
def process_image(img_path: str, directory: str, max_width: int) -> None: | |
before_size = os.path.getsize(img_path) | |
with Image.open(img_path) as img: | |
before_dims = img.size | |
img = add_transparent_border(img) | |
img = add_background(img) | |
img = resize_image(img, max_width) | |
after_dims = img.size | |
output_path = img_path.rsplit('.', 1)[0] + '.webp' | |
convert_to_webp(img, output_path) | |
after_size = os.path.getsize(output_path) | |
print_image_stats(img_path, before_size, after_size, before_dims, after_dims) | |
os.remove(img_path) | |
def resize_and_convert_directory(directory: str, max_width: int) -> None: | |
total_before_size = 0 | |
total_after_size = 0 | |
num_images = 0 | |
for filename in os.listdir(directory): | |
if filename.lower().endswith(('.png', '.jpg', '.jpeg')): | |
num_images += 1 | |
img_path = os.path.join(directory, filename) | |
before_size = os.path.getsize(img_path) | |
total_before_size += before_size | |
process_image(img_path, directory, max_width) | |
new_filename = filename.rsplit('.', 1)[0] + '.webp' | |
new_path = os.path.join(directory, new_filename) | |
after_size = os.path.getsize(new_path) | |
total_after_size += after_size | |
if num_images > 0: | |
avg_reduction = int((total_after_size / total_before_size) * 100) | |
total_before_mb = total_before_size / (1024 * 1024) | |
total_after_mb = total_after_size / (1024 * 1024) | |
print(f'\n--------------\nTotal Before: {total_before_mb:.2f} MB, Total After: {total_after_mb:.2f} MB') | |
print(f'Average Size Reduction: {100 - avg_reduction}%') | |
print(f'Total Images Processed: {num_images}') | |
def adapt_bg_directory(directory: str) -> None: | |
for filename in os.listdir(directory): | |
if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.webp')): | |
img_path = os.path.join(directory, filename) | |
with Image.open(img_path) as img: | |
img = add_transparent_border(img) | |
img = add_background(img) | |
img.save(img_path) | |
if __name__ == '__main__': | |
resize_and_convert_directory('public/images/articles/welcome-to-majordom', 1010) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment