Files
heros_web/scripts/build-equipment-icons.py

62 lines
2.1 KiB
Python

from __future__ import annotations
import argparse
from pathlib import Path
from PIL import Image
ROOT = Path(__file__).resolve().parents[1]
DEFAULT_SOURCE_DIR = ROOT / "tmp" / "imagegen"
OUTPUT_ROOT = ROOT / "src" / "assets" / "images" / "ui" / "equipment-icons"
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Build centered 128px and 32px equipment icons from transparent source art."
)
parser.add_argument("ids", nargs="+", help="Equipment ids whose <id>-alpha.png source should be built.")
parser.add_argument("--source-dir", type=Path, default=DEFAULT_SOURCE_DIR)
return parser.parse_args()
def fit_icon(source: Image.Image, size: int) -> Image.Image:
rgba = source.convert("RGBA")
bounds = rgba.getchannel("A").getbbox()
if bounds is None:
raise ValueError("source image has no visible pixels")
cropped = rgba.crop(bounds)
inner_size = max(1, round(size * 0.88))
scale = min(inner_size / cropped.width, inner_size / cropped.height)
resized_size = (
max(1, round(cropped.width * scale)),
max(1, round(cropped.height * scale)),
)
resized = cropped.resize(resized_size, Image.Resampling.LANCZOS)
canvas = Image.new("RGBA", (size, size), (0, 0, 0, 0))
offset = ((size - resized.width) // 2, (size - resized.height) // 2)
canvas.alpha_composite(resized, offset)
return canvas
def main() -> None:
args = parse_args()
for size in (128, 32):
(OUTPUT_ROOT / str(size)).mkdir(parents=True, exist_ok=True)
for item_id in args.ids:
source_path = args.source_dir / f"{item_id}-alpha.png"
if not source_path.exists():
raise FileNotFoundError(f"missing transparent source: {source_path}")
with Image.open(source_path) as source:
for size in (128, 32):
output_path = OUTPUT_ROOT / str(size) / f"{item_id}.png"
fit_icon(source, size).save(output_path, optimize=True)
print(f"Wrote {output_path.relative_to(ROOT)}")
if __name__ == "__main__":
main()