Files
Seb Hirsch a0ec2d5b8b Folder batch loader, Save Image source modes, headless test suite
Load Images From Folder walks a folder one image per run, queueing the next itself once the current run has finished, or emits every image as a list. Save Image (Seb) can save next to the source or replace it in place, atomically, keeping the format. tests/ drives a real headless Chromium against a scratch ComfyUI; see tests/README.md.
2026-09-13 17:10:58 +02:00

68 lines
2.4 KiB
Python

"""A mask painted in the editor must reach Python's MASK output.
Paint strokes over the centre of the editor's view (lon 0 / lat 0), Save, and
extract at yaw 0 with mask_mode 'editor': the centre must be white and the
corners black. 'core' must ignore the painting entirely.
"""
import glob
import json
import os
import time
import numpy as np
from playwright.sync_api import sync_playwright
from _common import (INPUT_DIR, PANO, add_read_node, editor_canvas_box, editor_save,
finish, forget, open_app, open_editor, require_server, state_json,
view_mask)
require_server()
forget(PANO)
UP = os.path.join(INPUT_DIR, "panorama_stickers")
rep = {}
with sync_playwright() as pw:
b, pg = open_app(pw)
add_read_node(pg, PANO, canvas_width=2048)
time.sleep(3)
open_editor(pg)
pg.locator('button[aria-label="Mask"]').first.click()
time.sleep(1.5)
box = editor_canvas_box(pg)
cx, cy = box["x"] + box["w"] * 0.5, box["y"] + box["h"] * 0.5
for row in range(5):
y = cy - 40 + row * 20
pg.mouse.move(cx - 150, y)
pg.mouse.down()
for i in range(1, 31):
pg.mouse.move(cx - 150 + i * 10, y, steps=2)
pg.mouse.up()
time.sleep(0.3)
time.sleep(1.5)
editor_save(pg, wait=9) # close -> rasterise -> upload -> state rewrite
st = state_json(pg)
b.close()
j = json.loads(st)
rep["mask_strokes_in_state"] = len((((j.get("painting") or {}).get("mask") or {}).get("strokes")) or [])
rep["painting_layer"] = j.get("painting_layer")
rep["uploaded"] = sorted(os.path.basename(p) for p in glob.glob(os.path.join(UP, "pano_mask_*.png")))
CAM = dict(yaw=0.0, pitch=0.0, fov=60.0, w=512, h=512, margin=0.0, state_json=st)
ed = view_mask(mask_mode="editor", **CAM)
core = view_mask(mask_mode="core", **CAM)
h, w = ed.shape
rep["editor_centre"] = round(float(ed[h // 2 - 10:h // 2 + 10, w // 2 - 10:w // 2 + 10].mean()), 3)
rep["editor_corner"] = round(float(ed[:20, :20].mean()), 3)
rep["editor_coverage_pct"] = round(float((ed > 0.5).mean() * 100), 2)
rep["core_min"] = round(float(core.min()), 3)
rep["VERDICT"] = {
"editor_uploaded_a_mask": bool(rep["painting_layer"] and rep["painting_layer"].get("mask")),
"python_mask_white_where_painted": rep["editor_centre"] > 0.6,
"python_mask_black_elsewhere": rep["editor_corner"] < 0.05,
"core_mode_ignores_painting": rep["core_min"] > 0.99,
}
forget(PANO)
finish(rep, all(rep["VERDICT"].values()))