from __future__ import annotations import shutil from pathlib import Path from PIL import Image ROOT = Path(__file__).resolve().parents[3] CANVAS = (900, 1125) MALE_PERSONAS = ("P5", "P7") MALE_EMPTY_HAIR_SLOTS = ( "hair-back-base", "hair-back-left", "hair-back-right", "hair-side-left-2", "hair-side-right-2", ) GENERATED_PERSONAS = ("P4", "P5", "P6", "P7") def parts_dir(persona: str) -> Path: return ROOT / f"apps/web/public/avatar/{persona.lower()}-live2d-generated/parts" def write_empty(path: Path) -> None: path.parent.mkdir(parents=True, exist_ok=True) Image.new("RGBA", CANVAS, (0, 0, 0, 0)).save(path, optimize=True) def clean_green_edge_spill(path: Path) -> int: image = Image.open(path).convert("RGBA") pixels = image.load() changed = 0 for y in range(image.height): for x in range(image.width): r, g, b, a = pixels[x, y] if a <= 80 and g > 135 and g > r + 35 and g > b + 35: if a <= 48: pixels[x, y] = (r, g, b, 0) else: pixels[x, y] = (r, min(g, max(r, b) + 18), b, a) changed += 1 if changed: image.save(path, optimize=True) return changed def main() -> int: for persona in MALE_PERSONAS: directory = parts_dir(persona) for part_id in MALE_EMPTY_HAIR_SLOTS: write_empty(directory / f"{part_id}.png") p7_outfit = parts_dir("P7") / "outfit.png" p5_outfit = parts_dir("P5") / "outfit.png" if p7_outfit.exists(): shutil.copyfile(p7_outfit, p5_outfit) cleaned = 0 for persona in GENERATED_PERSONAS: for path in parts_dir(persona).glob("*.png"): cleaned += clean_green_edge_spill(path) print(f"applied visual overrides for P5/P7 male silhouette; cleaned {cleaned} green edge pixels") return 0 if __name__ == "__main__": raise SystemExit(main())