from pathlib import Path import sys,json,subprocess,concurrent.futures from PIL import Image,ImageOps,ImageDraw,ImageFont phase=sys.argv[1] if len(sys.argv)>1 else 'final' root=Path(__file__).resolve().parents[3]/'caterium-six-proposals-20260918' src=root/('output/pdf' if phase=='final' else 'tmp/pdfs/'+phase) dest=root/'tmp/pdfs'/('render-'+phase) dest.mkdir(parents=True,exist_ok=True) poppler=Path.home()/'.cache/codex-runtimes/codex-primary-runtime/dependencies/native/poppler/Library/bin/pdftoppm.exe' pdfs=sorted(src.glob('*.pdf')) def render(pdf): for old in dest.glob(pdf.stem+'-*.png'):old.unlink() subprocess.run([str(poppler),'-scale-to','1200','-png',str(pdf),str(dest/pdf.stem)],check=True,capture_output=True) with concurrent.futures.ThreadPoolExecutor(max_workers=3) as pool:list(pool.map(render,pdfs)) font=ImageFont.truetype('C:/Windows/Fonts/arial.ttf',18) for pdf in pdfs: images=sorted(dest.glob(pdf.stem+'-*.png')) canvas=Image.new('RGB',(360*len(images),540),'#d9ded8');draw=ImageDraw.Draw(canvas) for i,file in enumerate(images): im=Image.open(file).convert('RGB');im.thumbnail((336,484)) canvas.paste(im,(i*360+12,34));draw.text((i*360+12,8),f'{pdf.stem} / {i+1}',font=font,fill='#15291e') canvas.save(dest/(pdf.stem+'-contact.jpg'),quality=94) report=json.loads((root/'tmp/pdfs'/phase/'report.json').read_text(encoding='utf-8')) problems=[] for row in report: for p,boxes in enumerate(row['layout']): for i,a in enumerate(boxes): if a['x']<35 or a['x']+a['w']>965 or a['y']<0 or a['y']+a['h']>1405:problems.append({'id':row['id'],'page':p+1,'kind':'bounds','box':a}) for b in boxes[i+1:]: if min(a['x']+a['w'],b['x']+b['w'])-max(a['x'],b['x'])>2 and min(a['y']+a['h'],b['y']+b['h'])-max(a['y'],b['y'])>2:problems.append({'id':row['id'],'page':p+1,'kind':'collision','a':a,'b':b}) (dest/'layout-problems.json').write_text(json.dumps(problems,ensure_ascii=False,indent=2),encoding='utf-8') if phase=='final': overview=Image.new('RGB',(1320,1390),'#e2e6e0');draw=ImageDraw.Draw(overview) heading=ImageFont.truetype('C:/Windows/Fonts/arialbd.ttf',25) for i,row in enumerate(report): col=i%3;r=i//3;x=col*440+20;y=r*685+18 draw.text((x,y),f'{i+1:02d} ยท {row["name"]}',font=heading,fill='#20362d') im=Image.open(dest/(Path(row['filename']).stem+'-1.png')).convert('RGB');im.thumbnail((400,596)) overview.paste(im,(x,y+46)) overview.save(root/'output'/'six-templates.png') print(f'Rendered {len(pdfs)} PDFs. Layout problems: {len(problems)}. {dest}')