Files
aetherbound-guild/tools/prepare_pty001_clean_master.py
T

74 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""Build a clean PTY-001 master and restore critical approved HUD geometry."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
ROOT = Path(__file__).resolve().parents[1]
PAGE = ROOT / "docs/design-authority/pages/PTY-001-party-line"
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--approved", type=Path, default=PAGE / "approved/v001/master.png")
parser.add_argument("--generated", type=Path, default=PAGE / "reconstruction/v001/static-master/clean-static-master.png")
parser.add_argument("--regions", type=Path, default=PAGE / "reconstruction/v001/static-master/dynamic-regions.json")
parser.add_argument("--output", type=Path, default=PAGE / "reconstruction/v001/static-master/party-line-static-master.png")
parser.add_argument("--review", type=Path, default=PAGE / "reconstruction/v001/static-master/static-master-review.png")
args = parser.parse_args()
authority = json.loads(args.regions.read_text(encoding="utf-8"))
expected = tuple(authority["design_size"])
approved = cv2.imread(str(args.approved), cv2.IMREAD_COLOR)
generated = cv2.imread(str(args.generated), cv2.IMREAD_COLOR)
if approved is None or generated is None:
raise SystemExit("approved or generated master could not be read")
if (approved.shape[1], approved.shape[0]) != expected or (generated.shape[1], generated.shape[0]) != expected:
raise SystemExit("master dimensions do not match dynamic-regions authority")
# Use the clean edit as the complete painted base. It reconstructs the yard
# behind actors and the cord coherently, avoiding rectangular patch seams.
result = generated.copy()
# Restore critical approved geometry that the cleanup edit simplified:
# the complete top status rail and the fixed relation clipboard icon.
result[0:142, 0:2048] = approved[0:142, 0:2048]
result[169:287, 1470:1588] = approved[169:287, 1470:1588]
# Pressure dots are state values. Inpaint only their circular interiors so
# the exact approved weight icon and outlined status slot remain untouched.
pressure_mask = np.zeros(approved.shape[:2], dtype=np.uint8)
for region in authority["regions"]:
if region.get("treatment") != "approved_inpaint":
continue
for x, y, radius in region.get("circles", []):
cv2.circle(pressure_mask, (x, y), radius + 2, 255, thickness=-1)
result = cv2.inpaint(result, pressure_mask, 5, cv2.INPAINT_TELEA)
args.output.parent.mkdir(parents=True, exist_ok=True)
cv2.imwrite(str(args.output), result, [cv2.IMWRITE_PNG_COMPRESSION, 7])
approved_preview = Image.open(args.approved).convert("RGB").resize((1024, 576), Image.Resampling.LANCZOS)
clean_preview = Image.open(args.output).convert("RGB").resize((1024, 576), Image.Resampling.LANCZOS)
review = Image.new("RGB", (2048, 636), "#17252c")
review.paste(approved_preview, (0, 60))
review.paste(clean_preview, (1024, 60))
draw = ImageDraw.Draw(review)
font = ImageFont.truetype("/System/Library/Fonts/Supplemental/Arial.ttf", 24)
draw.text((28, 17), "APPROVED COMPOSITION (dynamic state baked in)", fill="#f3d991", font=font)
draw.text((1052, 17), "CLEAN STATIC MASTER (runtime overlay ready)", fill="#9ed7aa", font=font)
args.review.parent.mkdir(parents=True, exist_ok=True)
review.save(args.review, optimize=True)
print(f"ABG_PTY001_STATIC_MASTER_PREPARED output={args.output} review={args.review}")
if __name__ == "__main__":
main()