Engine comparison

Same Arabic invoice. Five PDF engines.

Counts below come from verify-textlayer.py (pypdf) — the same script wired into ArabDoc CI. Pass requires zero presentation forms and non-zero base Arabic. Be fair: with a real Arabic font, some libraries (e.g. react-pdf, DomPDF) can pass that numeric check and still mangle shaping, table direction, or copy order — use the screenshots and paste samples. jsPDF + reshaper often scores 0/0 (no real Arabic in the text layer at all).

Text layer (the part PNG review cannot see)

Engine Base Arabic Presentation forms Verdict
jsPDF + arabic-reshaper + bidi-js 0 0 fail
@react-pdf/renderer (direction: rtl) 199 0 pass
pdfmake + Noto Naskh Arabic 0 0 fail
DomPDF (PHP, DejaVu, dir=rtl) 165 0 pass
ArabDoc (Chromium + ToUnicode NFKC) 535 0 pass

What the correct line should be

فاتورة ضريبية — رقم INV-2026-08421 — البريد billing@nukhbat-jazira.sa
About the paste samples below. They are raw text-extractor output (pdfjs), not what a human reader sees after BiDi. Logical Arabic order can look scrambled in a plain textarea; that alone is not a fail. The scored metric is codepoint counts: presentation forms must be 0 and base Arabic > 0. Crops and full-page PNGs show visual shaping; download each PDF to copy from a real viewer yourself.

Zoomed failure crops

Same regions, 2× screenshots — failures should be obvious without zooming the full page.

Ligatures / letter joining

Header + seller name. Detached glyphs vs joined Naskh/Sans shaping.

jspdf
Ligatures / letter joining — jspdf
react-pdf
Ligatures / letter joining — react-pdf
arabdoc
Ligatures / letter joining — arabdoc

Table column order

Line-item table. First logical column should be rightmost in RTL.

jspdf
Table column order — jspdf
dompdf
Table column order — dompdf
arabdoc
Table column order — arabdoc

Latin isolation

IDs, emails, iPad 11", +12.4% — must not jump to the wrong side.

pdfmake
Latin isolation — pdfmake
react-pdf
Latin isolation — react-pdf
arabdoc
Latin isolation — arabdoc

Side by side

jsPDF + arabic-reshaper + bidi-js

jsPDF + arabic-reshaper + bidi-js page 1
FAIL base Arabic: 0 presentation forms: 0 → PASS on forms

Raw extractor output (pdfjs text layer), not a reading-order transcription. Word order may look wrong for Arabic; we score codepoints (presentation forms U+FB50–FEFF), not display order. Prefer downloading the PDF and copying from a real viewer if you want the browser’s BiDi reordering.

Download jspdf.pdf

@react-pdf/renderer (direction: rtl)

@react-pdf/renderer (direction: rtl) page 1
PASS base Arabic: 199 presentation forms: 0 → PASS on forms

Raw extractor output (pdfjs text layer), not a reading-order transcription. Word order may look wrong for Arabic; we score codepoints (presentation forms U+FB50–FEFF), not display order. Prefer downloading the PDF and copying from a real viewer if you want the browser’s BiDi reordering.

Download react-pdf.pdf

pdfmake + Noto Naskh Arabic

pdfmake + Noto Naskh Arabic page 1
FAIL base Arabic: 0 presentation forms: 0 → PASS on forms

Raw extractor output (pdfjs text layer), not a reading-order transcription. Word order may look wrong for Arabic; we score codepoints (presentation forms U+FB50–FEFF), not display order. Prefer downloading the PDF and copying from a real viewer if you want the browser’s BiDi reordering.

Download pdfmake.pdf

DomPDF (PHP, DejaVu, dir=rtl)

DomPDF (PHP, DejaVu, dir=rtl) page 1
PASS base Arabic: 165 presentation forms: 0 → PASS on forms

Raw extractor output (pdfjs text layer), not a reading-order transcription. Word order may look wrong for Arabic; we score codepoints (presentation forms U+FB50–FEFF), not display order. Prefer downloading the PDF and copying from a real viewer if you want the browser’s BiDi reordering.

Download dompdf.pdf

ArabDoc (Chromium + ToUnicode NFKC)

ArabDoc (Chromium + ToUnicode NFKC) page 1
PASS base Arabic: 535 presentation forms: 0 → PASS on forms

Raw extractor output (pdfjs text layer), not a reading-order transcription. Word order may look wrong for Arabic; we score codepoints (presentation forms U+FB50–FEFF), not display order. Prefer downloading the PDF and copying from a real viewer if you want the browser’s BiDi reordering.

Download arabdoc.pdf

Reproduce

From a clone of the ArabDoc repo, run the benchmark package to regenerate these numbers and this page. Setup details (including a live API target) are in the repository README / benchmark/README.md.

cd benchmark
npm install
npm run benchmark

Generated 2026-08-08T07:13:42.669Z · payload benchmark/payload.json