magicciv/tools/sprite-generation/engine/silhouette.py
2026-04-07 17:52:04 -07:00

58 lines
1.8 KiB
Python

"""Generate locked-state silhouettes from approved throne room sprites.
For each throne room layer, the t1 (tier 1) sprite defines the locked shape.
The silhouette is a dark filled mask preserving only the alpha channel —
players see the slot's shape but not the earned art.
"""
from __future__ import annotations
from pathlib import Path
from PIL import Image, ImageChops, ImageFilter
def generate_silhouette(
src_path: Path,
dst_path: Path,
fill_color: tuple[int, int, int, int] = (26, 20, 16, 216),
edge_glow: bool = True,
) -> None:
"""Create a filled dark shape silhouette from a sprite's alpha channel.
Args:
src_path: Path to the source RGBA sprite.
dst_path: Destination path for the silhouette PNG.
fill_color: RGBA fill for opaque pixels (default: dark brown at 85% opacity).
edge_glow: If True, add a subtle 1px inner edge highlight for depth.
"""
img = Image.open(src_path).convert("RGBA")
alpha = img.split()[3]
fill = Image.new("RGBA", img.size, fill_color)
fill.putalpha(alpha)
if edge_glow:
eroded = alpha.filter(ImageFilter.MinFilter(3))
edge_mask = ImageChops.subtract(alpha, eroded)
glow_color = (fill_color[0] + 40, fill_color[1] + 35, fill_color[2] + 30, 180)
glow = Image.new("RGBA", img.size, glow_color)
glow.putalpha(edge_mask)
fill = Image.alpha_composite(fill, glow)
dst_path.parent.mkdir(parents=True, exist_ok=True)
fill.save(dst_path)
def generate_silhouettes_for_layer(
layer: str,
t1_sprite_path: Path,
output_dir: Path,
) -> Path:
"""Generate a silhouette for a throne room layer from its t1 sprite.
Returns the output path.
"""
dst = output_dir / f"{layer}_silhouette.png"
generate_silhouette(t1_sprite_path, dst)
return dst