58 lines
1.8 KiB
Python
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
|