responsive_image_generator.py
1 # /// script 2 # requires-python: ">=3.11" 3 # dependencies = [ 4 # "pillow", 5 # "tyro", 6 # "thumbhash-python", 7 # ] 8 # /// 9 10 11 from PIL import Image, ImageOps 12 from pathlib import Path 13 import base64 14 from io import BytesIO 15 import tyro 16 from thumbhash import image_to_thumbhash, thumbhash_to_image 17 18 19 def generate_responsive_images(input_image_path: Path): 20 # Define the sizes and suffixes 21 sizes = [(320, "-small"), (640, "-medium"), (1024, "-large"), (1920, "-xlarge")] 22 23 # Create opt directory if it doesn't exist 24 opt_dir = input_image_path.parent / "opt" 25 opt_dir.mkdir(exist_ok=True) 26 27 # Extract the base filename 28 base_name = input_image_path.stem 29 ext = input_image_path.suffix 30 31 width = 200 32 new_height = 200 33 34 # Process each size 35 for width, suffix in sizes: 36 # Open the original image 37 with Image.open(input_image_path) as img: 38 img = ImageOps.exif_transpose(img) or img 39 # Calculate the new height maintaining the aspect ratio 40 aspect_ratio = img.height / img.width 41 new_height = int(width * aspect_ratio) 42 43 # Resize the image 44 resized_img = img.resize((width, new_height), Image.Resampling.LANCZOS) 45 46 # Save the resized image in opt directory (JPEG) 47 resized_image_path = opt_dir / f"{base_name}{suffix}{ext}" 48 resized_img.save(resized_image_path) 49 print(f"Saved resized image: {resized_image_path}") 50 51 # Save WebP version 52 webp_path = opt_dir / f"{base_name}{suffix}.webp" 53 resized_img.save(webp_path, format="WEBP", quality=85, method=6) 54 print(f"Saved WebP image: {webp_path}") 55 56 # thumbhash 57 thumbhash = image_to_thumbhash(str(input_image_path)) 58 thumbhash_image = thumbhash_to_image(thumbhash) 59 thumbhash_path = opt_dir / f"{base_name}-thumbhash.png" 60 thumbhash_image.save(thumbhash_path) 61 62 # Convert the thumbhash image to Base64 63 buffered = BytesIO() 64 thumbhash_image.save(buffered, format="PNG") 65 66 # Generate the Jekyll template insertion code 67 template_code = f""" 68 {{% include responsive_image.html base_image_name="{base_name}" alt="Your Alt Text Here" 69 width="{width}" height="{new_height}" %}} 70 """ 71 print("\nJekyll template insertion code:\n") 72 print(template_code) 73 74 75 def main(in_path: str): 76 input_path = Path(in_path) 77 if input_path.is_file(): 78 generate_responsive_images(input_path) 79 elif input_path.is_dir(): 80 for file in input_path.iterdir(): 81 if file.is_file() and file.suffix.lower() in [".jpg", ".jpeg", ".png"]: 82 generate_responsive_images(file) 83 84 85 if __name__ == "__main__": 86 tyro.cli(main)