68 lines
2.2 KiB
Python
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()
|