Field Notes · Arabic breaks silently, part three

Your Arabic PDF is fine.
What reads it is not.

A PDF looks correct, so it is trusted. But almost nothing that consumes one looks at it — and extraction is where Arabic falls apart, silently, while the page on screen stays perfect.

Procurement portals parse the text out of your submission. Search engines index it. Compliance tools scan it for terms. Applicant systems read CVs. None of them look at the page; they all extract.

So I tested what actually comes back out. Five Arabic strings, written into PDFs by four generators, read back by three extractors.

Nothing is reliable, and the ends invert

Generatorpypdfpdfminer.sixpoppler
Chrome (HTML → PDF)3/50/51/5
ReportLab (naive)0/55/50/5
ReportLab (+ reshaper)3/50/53/5
LibreOffice (.docx → PDF)5/50/52/5

ReportLab-naive extracts perfectly through pdfminer and fails every other reader. Chrome — the route most web tooling uses — is zero for five through pdfminer, which is what a great many document pipelines run.

You cannot pick a “good” PDF library or a “good” extractor.
Correctness belongs to the pair, and when you submit a PDF you do not control the reader on the other side.

Why pdfminer inverts

pdfminer is zero for five against three generators and five for five against exactly one — the only one that performs no text layout. That is not coincidence, and it explains the whole table.

ReportLab-naive writes characters into the PDF in logical order, because it does no shaping and no bidi. Chrome, LibreOffice and reshaped ReportLab all lay the line out visually first, so the file stores glyphs in visual order. pdfminer returns what is stored without re-applying bidi, so it is correct precisely when the generator was naive. pypdf and poppler apply their own reordering heuristics, which is why they land in between.

The question a PDF actually answers is not “is the Arabic correct”.
It is which order the text is stored in, and whether this reader re-applies bidi. No tool tells you either.

Three failure modes, not one

My first read of this was “Arabic comes back reversed”. That was too crude — only one failure in eleven was an actual reversal. Separating them matters, because they need different fixes and one of them is far more dangerous than the others.

ModeSourceExtracted
Reversed — visual order, reads backwardsمرحبا بكم في دولة الإماراتتاراملإا ةلود يف مكب ابحرم
Ligature — lam-alef returns as two letters, wrong orderالإماراتاإلمارات
Spacing — letters intact, boundaries lostالنسبة 2026 فيالنسبة2026في

The ligature mode is the one to fear. A reader skims straight past it — the difference is a single swapped pair inside a common word — so it survives human proofreading while still breaking exact-match search, keyword compliance checks and any automated comparison. It was the most common failure in the whole matrix: seventeen occurrences against nine reversals.

The same recipe, opposite verdicts

The ReportLab rows confirm part two from the other direction. ReportLab performs no complex-text layout, so there the arabic_reshaper recipe is genuinely required — it takes that generator from 0/5 to 3/5 through poppler. In Chrome, the same recipe corrupts the output. One rule, opposite results, decided entirely by whether the renderer already shapes.

What this does not cover

Microsoft Word itself, InDesign and LaTeX are untested. LibreOffice covers the .docx route — it is the dominant headless converter and the realistic path a Word file takes on its way to a portal — but it is a different engine from Word and may lay text out differently. InDesign and LaTeX are not installed on the machine I ran this on, and WeasyPrint could not run because it needs Pango. I would rather say that than imply coverage I do not have; the harness takes a new generator in about ten lines.

What to do about it

  • If a PDF containing Arabic will be read by software, test the round trip yourself. Do not assume it survived because the page looks right.
  • Where the recipient allows it, submit a format that carries text losslessly alongside the PDF.
  • If you generate PDFs programmatically, check which of the two rendering worlds your library lives in before adding or removing reshaping.
  • Search for a common word from your own document in the extracted text. If الإمارات does not match, nothing downstream will find it either.

The data

Every generator × extractor combination, with the text each one returned, is published as ArPDF on Hugging Face, alongside ArNum-TTS and ArShape.

The series: part one, speech · part two, the screen · part three, the page.