# -*- coding: utf-8 -*-
"""原创离线合成样例；不连接模型、不读取账户。输出位于脚本旁。
已有输入保留，修改输入后可以重跑。失败边界由 --negative 单独演示。
"""
from pathlib import Path
import sys, json, csv, math, io, hashlib, html, base64, re
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
BASE = Path(__file__).resolve().parent
NEG = '--negative' in sys.argv
def write(name, value):
    p=BASE/name; p.parent.mkdir(parents=True,exist_ok=True)
    if isinstance(value,bytes): p.write_bytes(value)
    else: p.write_text(value,encoding='utf-8',newline='')
def seed(name,value):
    if not (BASE/name).exists(): write(name,value)
def jwrite(name,value): write(name,json.dumps(value,ensure_ascii=False,indent=2))
def jseed(name,value):
    if not (BASE/name).exists(): jwrite(name,value)
def load(name): return json.loads((BASE/name).read_text(encoding='utf-8'))
def table(name,heads,rows):
    f=io.StringIO(newline='');w=csv.writer(f);w.writerow(heads);w.writerows(rows);write(name,f.getvalue())
def page(name,title,body):
    write(name,'<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>'+html.escape(title)+'</title><style>body{max-width:1000px;margin:2rem auto;padding:0 1rem;font:17px/1.7 system-ui}table{border-collapse:collapse}td,th{border:1px solid #aaa;padding:.5rem}pre{white-space:pre-wrap;overflow-wrap:anywhere}img,svg{max-width:100%;height:auto}a{color:#125caa}</style><h1>'+html.escape(title)+'</h1>'+body+'</html>')
def emit(data): print(json.dumps(data,ensure_ascii=False))

from PIL import Image,ImageDraw
if not (BASE/'mask.png').exists():
    im=Image.new('L',(16,12));d=ImageDraw.Draw(im);d.rectangle((1,1,3,3),fill=255);d.rectangle((8,2,10,4),fill=255);d.point((11,5),fill=255);im.save(BASE/'mask.png')
im=Image.open(BASE/'mask.png')
if NEG:im=im.convert('RGB')
if im.mode!='L':raise ValueError('彩色预览图不是单通道标签蒙版，需先确认输入含义')
foreground={(x,y) for y in range(im.height) for x in range(im.width) if im.getpixel((x,y))>=128}
def components(connectivity):
    todo=set(foreground);out=[];offsets=[(1,0),(-1,0),(0,1),(0,-1)]+([(1,1),(1,-1),(-1,1),(-1,-1)] if connectivity==8 else [])
    while todo:
        first=min(todo);todo.remove(first);group={first};queue=[first]
        while queue:
            x,y=queue.pop()
            for dx,dy in offsets:
                p=(x+dx,y+dy)
                if p in todo:todo.remove(p);group.add(p);queue.append(p)
        out.append(group)
    return out
rows=[];preview=im.convert('RGB').resize((320,240),Image.Resampling.NEAREST);draw=ImageDraw.Draw(preview)
for mode in [4,8]:
    for i,c in enumerate(components(mode),1):
        xs,ys=zip(*c);box=[min(xs),min(ys),max(xs)+1,max(ys)+1];rows.append([mode,i,len(c),*box])
        if mode==8:draw.rectangle(tuple(v*20 for v in box),outline='red',width=2);draw.text((box[0]*20,box[1]*20),str(i),fill='orange')
preview.save(BASE/'component-overlay.png');table('components.csv',['connectivity','component','area_px','x0','y0','x1_exclusive','y1_exclusive'],rows);emit({'four_count':len(components(4)),'eight_count':len(components(8)),'foreground_pixels':len(foreground)})
