64 lines
2.2 KiB
Python
64 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Build a labeled checkerboard contact sheet from transparent PNG assets."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageDraw
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--input-dir", type=Path, required=True)
|
|
parser.add_argument("--pattern", default="*.png")
|
|
parser.add_argument("--cols", type=int, default=4)
|
|
parser.add_argument("--output", type=Path, required=True)
|
|
return parser.parse_args()
|
|
|
|
|
|
def checker(size: tuple[int, int], step: int = 16) -> Image.Image:
|
|
image = Image.new("RGB", size, (238, 238, 238))
|
|
draw = ImageDraw.Draw(image)
|
|
for y in range(0, size[1], step):
|
|
for x in range(0, size[0], step):
|
|
if (x // step + y // step) % 2:
|
|
draw.rectangle((x, y, x + step - 1, y + step - 1), fill=(210, 210, 210))
|
|
return image
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_args()
|
|
files = sorted(args.input_dir.glob(args.pattern))
|
|
if not files:
|
|
raise SystemExit(f"no assets match {args.input_dir / args.pattern}")
|
|
if args.cols <= 0:
|
|
raise SystemExit("--cols must be positive")
|
|
|
|
cell_width = 300
|
|
cell_height = 330
|
|
art_size = 256
|
|
rows = (len(files) + args.cols - 1) // args.cols
|
|
sheet = Image.new("RGB", (args.cols * cell_width, rows * cell_height), (24, 29, 38))
|
|
draw = ImageDraw.Draw(sheet)
|
|
|
|
for index, path in enumerate(files):
|
|
x = (index % args.cols) * cell_width
|
|
y = (index // args.cols) * cell_height
|
|
panel = checker((art_size, art_size))
|
|
asset = Image.open(path).convert("RGBA")
|
|
asset.thumbnail((art_size, art_size), Image.Resampling.LANCZOS)
|
|
offset = ((art_size - asset.width) // 2, (art_size - asset.height) // 2)
|
|
panel.paste(asset, offset, asset)
|
|
sheet.paste(panel, (x + 22, y + 18))
|
|
draw.text((x + 22, y + 286), path.stem, fill=(244, 240, 224))
|
|
|
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
sheet.save(args.output, optimize=True)
|
|
print(f"CONTACT_SHEET_OK assets={len(files)} output={args.output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|