feat: improve first-session combat and visual assets
This commit is contained in:
61
scripts/build-equipment-icons.py
Normal file
61
scripts/build-equipment-icons.py
Normal file
@@ -0,0 +1,61 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user