Files

68 lines
2.8 KiB
Python
Executable File

#!/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 <pdf-dir> <png-dir> <font.ttf>
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'<word xMin="([\d.]+)" yMin="([\d.]+)" xMax="([\d.]+)" yMax="([\d.]+)">%s[^<]*</word>' % 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)