Files
heros_web/scripts/solidify-unit-alpha.py

68 lines
2.2 KiB
Python

from pathlib import Path
from PIL import Image, ImageChops, ImageFilter, ImageStat
from PIL.PngImagePlugin import PngInfo
ROOT = Path(__file__).resolve().parents[1]
UNIT_DIR = ROOT / "src" / "assets" / "images" / "units"
PROCESSING_VERSION = "solid-alpha-silhouette-v1"
def solid_alpha(value: int) -> int:
return 0 if value < 16 else 255
def unit_fill_color(image: Image.Image, mask: Image.Image) -> tuple[int, int, int, int]:
stat = ImageStat.Stat(image.convert("RGB"), mask=mask)
if not stat.count[0]:
return (54, 45, 34, 255)
red, green, blue = stat.mean
return (max(30, round(red * 0.45)), max(26, round(green * 0.45)), max(22, round(blue * 0.45)), 255)
def solidify_image(image: Image.Image) -> Image.Image:
image = image.convert("RGBA")
red, green, blue, alpha = image.split()
fixed_alpha = alpha.point(solid_alpha)
solid = Image.merge("RGBA", (red, green, blue, fixed_alpha))
transparent = Image.new("RGBA", image.size, (0, 0, 0, 0))
solid = Image.composite(solid, transparent, fixed_alpha)
silhouette = fixed_alpha.filter(ImageFilter.MaxFilter(15)).filter(ImageFilter.MinFilter(7))
silhouette = silhouette.point(lambda value: 255 if value >= 255 else 0)
fill_mask = ImageChops.subtract(silhouette, fixed_alpha)
fill = Image.new("RGBA", image.size, unit_fill_color(image, fixed_alpha))
body = Image.composite(fill, transparent, fill_mask)
return Image.alpha_composite(body, solid)
def solidify_unit_alpha(path: Path) -> bool:
with Image.open(path) as source:
if source.info.get("heros_unit_alpha") == PROCESSING_VERSION:
return False
image = source.convert("RGBA")
fixed = solidify_image(image)
if ImageChops.difference(image, fixed).getbbox() is None:
return False
png_info = PngInfo()
png_info.add_text("heros_unit_alpha", PROCESSING_VERSION)
fixed.save(path, optimize=True, pnginfo=png_info)
return True
def main() -> None:
changed = 0
for path in sorted(UNIT_DIR.glob("unit-*.png")):
if solidify_unit_alpha(path):
changed += 1
print(f"Solidified alpha in {changed} unit sprite sheets.")
if __name__ == "__main__":
main()