← back to Japan Enrich

make_sangetsu_swatches.py

47 lines

#!/usr/bin/env python3
"""
Downscale the full-res Sangetsu colorway images (images/sangetsu/, ~2.1 GB, fetched
by enrich_sangetsu.py for hex accuracy) into small 256px card swatches
(images/sangetsu-sw/) so the viewer can serve /img/sangetsu/<sku> self-contained
and ship disk-safe to Kamatera — same pattern as the Greenland swatches.

$0 local (Pillow). Skip-existing + concurrency. Originals are left untouched.
"""
import os, concurrent.futures as cf
from PIL import Image

SRC = "images/sangetsu"
DST = "images/sangetsu-sw"
MAX = 256
os.makedirs(DST, exist_ok=True)

def one(fn):
    if not fn.lower().endswith((".jpg", ".jpeg")):
        return 0
    dst = os.path.join(DST, fn)
    if os.path.exists(dst) and os.path.getsize(dst) > 0:
        return 0
    try:
        with Image.open(os.path.join(SRC, fn)) as im:
            im = im.convert("RGB")
            im.thumbnail((MAX, MAX))
            im.save(dst, "JPEG", quality=82, optimize=True)
        return 1
    except Exception:
        return 0

def main():
    files = [f for f in os.listdir(SRC) if f.lower().endswith((".jpg", ".jpeg"))]
    print(f"sangetsu swatches: {len(files)} source images -> {DST} (max {MAX}px)", flush=True)
    made = skipped = 0
    with cf.ThreadPoolExecutor(max_workers=8) as ex:
        for i, r in enumerate(ex.map(one, files), 1):
            made += r; skipped += (1 - r)
            if i % 2000 == 0:
                print(f"  {i}/{len(files)} ({made} made)", flush=True)
    total = len([f for f in os.listdir(DST) if f.lower().endswith((".jpg", ".jpeg"))])
    print(f"DONE: {made} made this run; {total} swatches in {DST}", flush=True)

if __name__ == "__main__":
    main()