#!/usr/bin/env python3 """Crop the item table out of each probe PDF and stack the crops under a Pillow/libraqm reference line. Usage: compare.py The reference is the same probe text drawn by Pillow's RAQM layout engine (libraqm -> HarfBuzz) with the same Noto Sans Devanagari file: an independent shaper, there to show what "correct" looks like. """ import re, subprocess, sys from pathlib import Path from PIL import Image, ImageDraw, ImageFont pdfdir, pngdir, fontfile = Path(sys.argv[1]), Path(sys.argv[2]), sys.argv[3] PROBE = "क्षत्रिय ज्ञान श्री द्वार कर्म कि प्रिय" DPI = 200 ENGINES = [ ("openpdf", "OpenPDF 3.0.5, defaults"), ("itext", "iText Core 9.8.0, defaults"), ("flyingsaucer", "Flying Saucer 10.7.0, defaults"), ("openpdf-fop", "OpenPDF + Apache FOP 2.11 on the classpath"), ("openpdf-jdk-actualtext", "OpenPDF GlyphLayoutManager (JDK shaper)"), ("flyingsaucer-shaped", "Flying Saucer + OpenPDF LayoutProcessor"), ] def box(pdf, word): out = subprocess.run(["pdftotext", "-bbox", str(pdf), "-"], capture_output=True, text=True).stdout hits = re.findall(r'%s[^<]*' % re.escape(word), out) return [tuple(map(float, h)) for h in hits] font_big = ImageFont.truetype(fontfile, 40, layout_engine=ImageFont.Layout.RAQM) font_lbl = ImageFont.truetype(fontfile, 22, layout_engine=ImageFont.Layout.RAQM) rows = [] ref = Image.new("RGB", (1500, 120), "white") d = ImageDraw.Draw(ref) d.text((10, 6), "reference: Pillow + libraqm (HarfBuzz), same font", font=font_lbl, fill="#555") d.text((10, 44), PROBE, font=font_big, fill="black") rows.append(ref) for engine, label in ENGINES: pdf = pdfdir / f"probe-{engine}.pdf" if not pdf.exists(): print("skip", engine, "(no probe pdf)") continue item = box(pdf, "Item")[0] total = box(pdf, "Total")[-1] y0 = int((item[1] - 8) * DPI / 72) y1 = int((total[3] + 62) * DPI / 72) subprocess.run(["pdftoppm", "-r", str(DPI), "-png", "-singlefile", "-x", str(int(36 * DPI / 72)), "-y", str(y0), "-W", "1500", "-H", str(y1 - y0), str(pdf), str(pngdir / f"crop-{engine}")], check=True) img = Image.open(pngdir / f"crop-{engine}.png").convert("RGB") band = Image.new("RGB", (1500, 34), "#f4f5f7") ImageDraw.Draw(band).text((10, 4), label, font=font_lbl, fill="#222") rows.append(band) rows.append(img) (pngdir / f"crop-{engine}.png").unlink() W = 1500 H = sum(r.height for r in rows) out = Image.new("RGB", (W, H), "white") y = 0 for r in rows: out.paste(r, (0, y)) y += r.height out = out.convert("P", palette=Image.ADAPTIVE, colors=32) out.save(pngdir / "shaping-comparison.png", optimize=True) print("wrote", pngdir / "shaping-comparison.png", out.size)