DEV Community

Mahmoud Ibrahim — Confileo
Mahmoud Ibrahim — Confileo

Posted on

I printed Arabic to PDF with 13 fonts. Only one produced text you can search

If you generate PDFs from HTML with Puppeteer, Playwright or headless Chrome, and any of your users write in Arabic, there is a good chance your PDFs contain no searchable Arabic text. They look perfect. You cannot tell by opening them. You find out when a user says "I can't copy the name out of the invoice", or when an applicant tracking system rejects a CV that reads fine to a human.

I ran into this while building a text-to-PDF feature, and then measured it properly: 13 fonts, the same Arabic paragraph, printed by headless Chrome, read back with pdf.js. One font passed.

The test

The document is four short lines: a title (خطاب تعريف), a sentence that contains ordinary words such as الموظف, a line that mixes Arabic with Latin text and digits, and three words chosen because they contain the lam-alef ligature: الأمر، الآن، لإدارة.

Each font is embedded with @font-face, the page is printed with page.pdf(), and the PDF goes straight into pdfjs-dist to get the text layer. Three checks:

  1. Presentation forms. Are the stored characters real Arabic letters (U+0600–U+06FF), or the Unicode presentation forms (U+FB50–FDFF, U+FE70–FEFF) that describe a letter's shape instead of the letter?
  2. Lam-alef order. Do الأمر / الآن / لإدارة come back as typed?
  3. Whole words. How many of the 18 Arabic words can a plain text search find?

The results

Chrome 135, pdf.js 4.8, September 2026:

Font Stored as لا ligature Words found
Amiri Regular real letters in order 15 / 18
Amiri Bold real letters in order 16 / 18
IBM Plex Sans Arabic presentation forms 0 / 18
Noto Sans Arabic presentation forms 0 / 18
Arial presentation forms 0 / 18
Tahoma presentation forms 0 / 18
Times New Roman presentation forms 0 / 18
Segoe UI presentation forms 1 / 18
Traditional Arabic presentation forms 0 / 18
Simplified Arabic presentation forms 0 / 18
Arabic Typesetting presentation forms 0 / 18
Sakkal Majalla presentation forms 1 / 18
Andalus presentation forms 0 / 18

An earlier run with web fonts told the same story. Readex Pro, Scheherazade New and Lateef stored real letters but reversed the lam-alef ligature; Noto Naskh Arabic, Noto Kufi Arabic, Cairo, Almarai and Tajawal stored presentation forms.

The two or three words Amiri "misses" are not a font problem: pdf.js sometimes puts a space inside a word where one text run ends and the next begins. All the letters are there and in order.

Why this happens

Arabic is cursive. Most letters have up to four shapes depending on their neighbours, and some pairs fuse into a single glyph. Chrome shapes the text with HarfBuzz and writes the resulting glyphs into the PDF. For the text to be extractable, the PDF also needs a ToUnicode map: glyph number → the characters it represents.

For most Arabic fonts, Chrome cannot trace a shaped glyph back to the character that produced it, so the map points at the presentation-form codepoint for that shape. The file renders correctly, because rendering uses the glyphs. Extraction uses the map, so what you copy is a different string from what you typed. Search for الموظف and you are searching for letters that are not in the file.

The ligature is the second trap. لا is one glyph standing for two letters, lam followed by alef. Several fonts get every other letter right and then map that glyph back as alef + lam, reversed. That breaks every word where ال is followed by أ, إ or آ, which in Arabic is a lot of words.

Check your own font

I put the test in a small repo so it can run in CI next to your templates:

git clone https://github.com/mahmoudQq2023/arabic-pdf-fonts
cd arabic-pdf-fonts && npm install
node check-font.mjs ./fonts/YourFont-Regular.ttf ./fonts/YourFont-Bold.ttf
Enter fullscreen mode Exit fullscreen mode
YourFont-Regular.ttf   BROKEN: presentation forms (text not searchable)  (0/18 words searchable)
Amiri-Regular.ttf      OK: real letters, lam-alef in order  (15/18 words searchable)
Enter fullscreen mode Exit fullscreen mode

It exits with code 1 if any font fails, and --json gives you something to assert on. The results page is at mahmoudqq2023.github.io/arabic-pdf-fonts.

What I changed in production

  • Amiri is embedded for every Arabic document, including a real Bold file. Synthetic bold draws each glyph as its own run, which can split a bold heading into one run per letter.
  • No font picker. Offering Arabic fonts that look nicer but produce unsearchable files felt like a trap for users who will never know why their CV is not being parsed.
  • No promise about harakat. Diacritics (U+064B–0652) rendered correctly in every font and came back as U+0000 in all of them. Copy gives you the base letters.
  • A round-trip test in the repo. The page never shows this bug, so only a test that reads the PDF back will catch a regression when someone swaps a font later.

The feature this came from is Confileo's text to PDF converter. If you only need to turn Arabic text into a searchable PDF, you can use it directly; if you generate PDFs yourself, run the checker on your fonts before your users find the problem for you.

Top comments (0)