from PIL import Image, ImageDraw, ImageFont
import os, glob, statistics, math

PROJ='/Users/bot1/Volumes/root_for_ai/AI工作区/良渚_IP授权PDF直接修改_20260611_1117'
IN=f'{PROJ}/work/rendered_before'
OUT=f'{PROJ}/work/patched_pages_stable'
os.makedirs(OUT, exist_ok=True)

FONT='/System/Library/Fonts/PingFang.ttc'
FONT_HEI='/System/Library/Fonts/STHeiti Light.ttc'

def font(size):
    for fp in [FONT, FONT_HEI, '/System/Library/Fonts/Supplemental/Arial Unicode.ttf']:
        try:
            return ImageFont.truetype(fp, size)
        except Exception:
            pass
    return ImageFont.load_default()

BODY=(52,47,42)
TITLE=(56,48,42)
GOLD=(175,129,55)
OFFWHITE=(246,244,238)
WHITE=(248,247,244)

def sample_fill(im, box, fallback=OFFWHITE):
    x0,y0,x1,y1=map(int, box)
    W,H=im.size
    pix=im.load(); pts=[]
    # sample four strips just outside the box; prefer light background
    samples=[]
    for x in range(max(0,x0-40), min(W,x1+40), max(1,(x1-x0)//30 or 1)):
        for y in [max(0,y0-18), min(H-1,y1+18)]: samples.append((x,y))
    for y in range(max(0,y0-20), min(H,y1+20), max(1,(y1-y0)//10 or 1)):
        for x in [max(0,x0-18), min(W-1,x1+18)]: samples.append((x,y))
    for x,y in samples:
        r,g,b=pix[x,y][:3]
        if min(r,g,b)>130:
            pts.append((r,g,b))
    if not pts:
        return fallback
    return tuple(int(statistics.median([p[i] for p in pts])) for i in range(3))

def rect(draw, box, fill, pad=0):
    x0,y0,x1,y1=box
    draw.rectangle((x0-pad,y0-pad,x1+pad,y1+pad), fill=fill)

def write(draw, xy, s, size, fill=BODY, spacing=4):
    draw.multiline_text(xy, s, font=font(size), fill=fill, spacing=spacing)

def patch(page_no, ops):
    im=Image.open(f'{IN}/page_{page_no:02d}.png').convert('RGB')
    d=ImageDraw.Draw(im)
    for op in ops:
        fill=op.get('fill')
        if fill is None:
            fill=sample_fill(im, op['box'])
        rect(d, op['box'], fill, op.get('pad',3))
        if op.get('text'):
            write(d, op['xy'], op['text'], op.get('size',24), op.get('color',BODY), op.get('spacing',4))
    im.save(f'{OUT}/page_{page_no:02d}.jpg', quality=96)

# Copy untouched pages
for fp in sorted(glob.glob(f'{IN}/page_*.png')):
    Image.open(fp).convert('RGB').save(f'{OUT}/{os.path.splitext(os.path.basename(fp))[0]}.jpg', quality=96)

# Stable edits: only boxes where the old content can be fully removed and redrawn without touching images/neighboring modules.
edits={
    # P4: remove the dangling second line and redraw完整句；保留上一行长句不硬塞，避免叠字
    4:[
        {'box':(96,394,620,436),'xy':(104,401),'text':'标志着中华五千年文明史得到了国际社会的普遍认可。','size':25,'fill':OFFWHITE},
    ],
    # P5: split 广泛认可 and typo 堤坝
    5:[
        {'box':(84,174,1048,248),'xy':(88,182),'text':'良渚古城遗址，2019年正式列入《世界遗产名录》——标志着中华五千年文明史获得国际学界\n广泛认可。','size':26,'spacing':7,'fill':OFFWHITE},
        {'box':(875,572,1118,610),'xy':(884,578),'text':'最早的堤坝系统','size':31,'fill':OFFWHITE},
    ],
    # P8: fix only the very visible 机制断行 by blanking tiny orphan 制 and adding机制 on previous line end area
    8:[
        {'box':(184,552,760,600),'xy':(188,560),'text':'余名嘉宾参加，成为中华文明与世界文明交流互鉴的固定国家级对话机制。','size':23,'fill':OFFWHITE},
        {'box':(184,392,760,438),'xy':(188,398),'text':'「良渚论坛」已成功举办三届，累计吸引全球115个国家和地区的1300','size':23,'fill':OFFWHITE},
        {'box':(943,382,1534,430),'xy':(948,390),'text':'二期工程总建筑面积约6.5万平方米，已列入重要建设计划。','size':23,'fill':OFFWHITE},
    ],
    # P9: obvious title punctuation and 产业集聚
    9:[
        {'box':(82,78,1225,154),'xy':(86,91),'text':'市场热度飙升——从「文明遗产」到「文化现象」','size':56,'color':TITLE,'fill':OFFWHITE},
        {'box':(846,462,1178,520),'xy':(852,469),'text':'1000余家  产业集聚','size':36,'color':GOLD,'fill':OFFWHITE},
    ],
    # P13: title spacing
    13:[
        {'box':(86,78,870,154),'xy':(91,92),'text':'市场现状：品牌的三重焦虑','size':56,'color':TITLE,'fill':OFFWHITE},
    ],
    # P14: first paragraph split and footer typo only, do not change keyword grid to avoid duplicate
    14:[
        {'box':(105,220,1385,318),'xy':(108,230),'text':'良渚代表的不只是中华民族屹立于世界之巅的「文明高度」，更是融入日常、延续千年的\n一套中国式的「生活哲学」。','size':35,'spacing':8,'fill':OFFWHITE},
        {'box':(1380,848,1518,880),'xy':(1384,852),'text':'IP 内核价值引擎','size':18,'fill':OFFWHITE},
    ],
    # P15: paragraph line break after 现/代
    15:[
        {'box':(88,270,1420,350),'xy':(92,280),'text':'良渚先民用最凝练的直线与圆，创造了外方内圆的玉琮；以精准的阴刻线条，在玉石上刻下细如发丝的神人兽面纹。\n这是一种跨越时空、直抵现代设计内核的几何美学语言。它不喧哗，却有无声的惊雷。','size':25,'spacing':8,'fill':OFFWHITE},
    ],
    # P17: title spacing
    17:[
        {'box':(86,78,1010,154),'xy':(91,92),'text':'治愈时代焦虑的秩序感与田园梦','size':56,'color':TITLE,'fill':OFFWHITE},
    ],
    # P21: visible title split and caption split; leave body columns untouched to avoid overlay collisions
    21:[
        {'box':(88,80,1025,155),'xy':(92,94),'text':'史前时代的系统工程与极致匠心','size':56,'color':TITLE,'fill':OFFWHITE},
        {'box':(910,420,1230,468),'xy':(914,427),'text':'1毫米 / 4–5条阴线','size':32,'color':GOLD,'fill':OFFWHITE},
        {'box':(910,468,1188,524),'xy':(914,473),'text':'玉器纹饰的雕刻精度——\n肉眼几乎不可辨识的史前微雕','size':18,'spacing':3,'fill':OFFWHITE},
    ],
    # P22: title and HEX typo #D8CBC0
    22:[
        {'box':(84,78,880,155),'xy':(88,92),'text':'一整套属于东方的色彩体系','size':56,'color':TITLE,'fill':OFFWHITE},
        {'box':(1188,622,1262,648),'xy':(1191,626),'text':'#D8CBC0','size':13,'fill':OFFWHITE},
    ],
    # P23: title spacing
    23:[
        {'box':(90,78,530,154),'xy':(94,92),'text':'良渚色彩系统','size':56,'color':TITLE,'fill':OFFWHITE},
    ],
    # P28:重磅断行，redraw only paragraph white area
    28:[
        {'box':(88,300,560,430),'xy':(92,310),'text':'以周大福高级珠宝线传承工艺打造联名产品，重磅上线\n周大福品牌荟馆店，实现文化与产品的双\n「传承」概念营销。','size':25,'spacing':9,'fill':OFFWHITE},
    ],
    # P35:匠心精神断行
    35:[
        {'box':(1110,485,1538,602),'xy':(1114,494),'text':'品牌冠名或联合出品专题短片（「极简美学」「匠心精神」\n「远古密码」等主题），良渚全媒体矩阵\n联合推送。','size':22,'spacing':7,'fill':OFFWHITE},
    ],
    # P36: remove hyphen before 05 and keep number aligned
    36:[
        {'box':(515,390,650,438),'xy':(566,395),'text':'05','size':42,'color':TITLE,'fill':OFFWHITE},
    ],
}

for pg, ops in edits.items():
    patch(pg, ops)

# assemble high-quality raster PDF
imgs=[]
for fp in sorted(glob.glob(f'{OUT}/page_*.jpg')):
    imgs.append(Image.open(fp).convert('RGB'))
final=f'{PROJ}/deliverables/良渚IP授权介绍2026_稳定修正版.pdf'
imgs[0].save(final, save_all=True, append_images=imgs[1:], resolution=144.0, quality=95)
print(final)
print(len(imgs))
