Skip to content

Instantly share code, notes, and snippets.

@andreialba
Created April 8, 2026 10:47
Show Gist options
  • Select an option

  • Save andreialba/0bd9a09eec0dffd6ae56748178cd511f to your computer and use it in GitHub Desktop.

Select an option

Save andreialba/0bd9a09eec0dffd6ae56748178cd511f to your computer and use it in GitHub Desktop.
Image Distributor & Thumbnail Generator
#!/usr/bin/env python3
"""
Image Distributor & Thumbnail Generator
----------------------------------------
1. Creates 10 subfolders inside a target directory
2. Randomly distributes ~1000 images across them (~100 each)
3. For each image, generates 10 WordPress thumbnail sizes
Usage:
python generate_thumbnails.py /path/to/your/images
Requirements:
pip install Pillow
"""
import os
import sys
import random
import shutil
from pathlib import Path
from PIL import Image
# ── Configuration ─────────────────────────────────────────────────────────────
NUM_FOLDERS = 10
# 10 WordPress / web thumbnail sizes — all within 1024px max dimension
THUMBNAIL_SIZES = [
(100, 100), # WooCommerce tiny
(150, 150), # WP default thumbnail (square)
(250, 250), # Sidebar / widget square
(300, 300), # WP medium square
(320, 240), # Mobile small landscape
(400, 300), # Card / widget landscape
(600, 400), # Blog featured image
(768, 432), # Tablet 16:9
(800, 600), # Medium-large landscape
(1024, 576), # Full-width 16:9
]
# Supported input image extensions
IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".tiff", ".gif"}
# ── Helpers ───────────────────────────────────────────────────────────────────
def collect_images(source_dir: Path) -> list[Path]:
"""Return a shuffled list of image files in source_dir (non-recursive)."""
images = [
f for f in source_dir.iterdir()
if f.is_file() and f.suffix.lower() in IMAGE_EXTENSIONS
]
random.shuffle(images)
return images
def create_folders(base_dir: Path) -> list[Path]:
"""Create 10 numbered subfolders and return their paths."""
folders = []
for i in range(1, NUM_FOLDERS + 1):
folder = base_dir / f"batch_{i:02d}"
folder.mkdir(exist_ok=True)
folders.append(folder)
return folders
def distribute_images(images: list[Path], folders: list[Path]) -> dict[Path, list[Path]]:
"""
Move images into folders as evenly as possible.
Returns a dict mapping each folder to its list of moved images.
"""
mapping: dict[Path, list[Path]] = {f: [] for f in folders}
for idx, img_path in enumerate(images):
target_folder = folders[idx % NUM_FOLDERS]
dest = target_folder / img_path.name
# Handle filename collisions
if dest.exists():
stem = img_path.stem
suffix = img_path.suffix
dest = target_folder / f"{stem}_{idx}{suffix}"
shutil.move(str(img_path), dest)
mapping[target_folder].append(dest)
return mapping
def make_thumbnail(src: Path, folder: Path, width: int, height: int) -> None:
"""
Create a thumbnail of (width x height) from src image.
Uses LANCZOS resampling. Fits the image within the box without cropping.
Saves as JPEG regardless of source format.
"""
thumb_name = f"{src.stem}-thumb-{width}x{height}.jpg"
thumb_path = folder / thumb_name
with Image.open(src) as img:
# Convert palette / RGBA images so they save cleanly as JPEG
if img.mode in ("P", "RGBA", "LA"):
img = img.convert("RGB")
elif img.mode != "RGB":
img = img.convert("RGB")
img_copy = img.copy()
img_copy.thumbnail((width, height), Image.LANCZOS)
img_copy.save(thumb_path, "JPEG", quality=85, optimize=True)
def generate_thumbnails(mapping: dict[Path, list[Path]]) -> None:
"""Generate all thumbnail sizes for every image in every folder."""
total_thumbs = 0
for folder, images in mapping.items():
print(f"\n 📁 {folder.name} ({len(images)} images)")
for img_path in images:
for width, height in THUMBNAIL_SIZES:
try:
make_thumbnail(img_path, folder, width, height)
total_thumbs += 1
except Exception as e:
print(f" ⚠️ Skipped thumbnail {width}x{height} for {img_path.name}: {e}")
thumb_count = len(images) * len(THUMBNAIL_SIZES)
print(f" ✅ {thumb_count} thumbnails generated")
print(f"\n 🎉 Total thumbnails created: {total_thumbs}")
# ── Main ──────────────────────────────────────────────────────────────────────
def main():
if len(sys.argv) < 2:
print("Usage: python generate_thumbnails.py /path/to/your/images")
sys.exit(1)
source_dir = Path(sys.argv[1]).resolve()
if not source_dir.is_dir():
print(f"Error: '{source_dir}' is not a valid directory.")
sys.exit(1)
print(f"\n🔍 Scanning: {source_dir}")
images = collect_images(source_dir)
print(f" Found {len(images)} image(s)")
if not images:
print("No supported images found. Supported formats: JPG, PNG, WEBP, BMP, TIFF, GIF")
sys.exit(0)
print(f"\n📂 Creating {NUM_FOLDERS} folders...")
folders = create_folders(source_dir)
print(f"\n🔀 Distributing images across folders...")
mapping = distribute_images(images, folders)
for folder, imgs in mapping.items():
print(f" {folder.name}: {len(imgs)} images")
print(f"\n🖼️ Generating thumbnails ({len(THUMBNAIL_SIZES)} sizes per image)...")
print(f" Sizes: {', '.join(f'{w}x{h}' for w, h in THUMBNAIL_SIZES)}")
generate_thumbnails(mapping)
print("\n✅ All done!")
print(f" 📁 {NUM_FOLDERS} folders")
print(f" 🖼️ {len(images)} original images distributed")
print(f" 🔖 Up to {len(images) * len(THUMBNAIL_SIZES)} thumbnails generated")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment