Files
aetherbound-guild/tools/verify_identity_anchors.py

74 lines
2.8 KiB
Python

#!/usr/bin/env python3
"""Verify normalized Phase 7 full-body identity anchors."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from PIL import Image
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--input-dir", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--expected-count", type=int, default=4)
parser.add_argument("--pixels", type=int, default=512)
return parser.parse_args()
def inspect(path: Path, pixels: int) -> dict[str, object]:
image = Image.open(path).convert("RGBA")
visible = [(r, g, b, a) for r, g, b, a in image.getdata() if a >= 16]
bound = image.getchannel("A").point(lambda value: 255 if value >= 16 else 0).getbbox()
corners = [
image.getpixel((0, 0))[3],
image.getpixel((pixels - 1, 0))[3],
image.getpixel((0, pixels - 1))[3],
image.getpixel((pixels - 1, pixels - 1))[3],
] if image.size == (pixels, pixels) else []
green_spill = sum(1 for red, green, blue, _ in visible if green - red > 50 and green - blue > 50)
errors: list[str] = []
if image.size != (pixels, pixels):
errors.append(f"dimensions {image.size}")
if not visible or not bound:
errors.append("empty visible content")
if corners and any(corners):
errors.append(f"opaque corners {corners}")
if bound and not 0.82 <= (bound[3] - bound[1]) / pixels <= 0.90:
errors.append(f"height fraction {(bound[3] - bound[1]) / pixels:.4f}")
if bound and bound[3] != round(pixels * 0.94):
errors.append(f"feet baseline {bound[3]}")
if green_spill:
errors.append(f"green spill {green_spill}")
return {
"path": path.as_posix(),
"ok": not errors,
"errors": errors,
"dimensions": list(image.size),
"content_bound": list(bound) if bound else None,
"visible_pixels": len(visible),
"green_spill_pixels": green_spill,
}
def main() -> None:
args = parse_args()
files = sorted(args.input_dir.glob("*-anchor.png"))
items = [inspect(path, args.pixels) for path in files]
errors = [error for item in items for error in item["errors"]]
if len(files) != args.expected_count:
errors.append(f"expected {args.expected_count} anchors, found {len(files)}")
report = {"ok": not errors, "count": len(files), "errors": errors, "items": items}
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8")
if errors:
raise SystemExit("IDENTITY_ANCHOR_VERIFY_FAILED " + "; ".join(errors[:8]))
print(f"IDENTITY_ANCHOR_VERIFY_OK anchors={len(files)} output={args.output}")
if __name__ == "__main__":
main()