Matterhorn 31-009 · PDF/UA-1 UA1:7.21.4.1-1
Font not embedded: why substitution corrupts Hebrew
PDF/UA-1 requires every font used for visible text to be embedded, so the document renders and extracts identically everywhere. A glyph counts as rendered if the text render mode is not 3.
The condition, as the protocol states it. “For a font used by text intended to be rendered the font program is not embedded.”
Matterhorn Protocol 1.1, checkpoint 31, index 31-009, section UA1:7.21.4.1-1. Software can decide this one on its own.
What a screen reader actually does
Substituted fonts change glyph-to-character mapping, so extracted text can differ from what is displayed — especially for Hebrew, where substitution frequently produces mojibake.
What the requirement is
PDF/UA-1 clause 7.21.4.1: for a font used by text intended to be rendered, the font program shall be embedded. No exemptions, including for the fourteen standard fonts.
In the file, embedding means the font descriptor carries the program:
18 0 obj
<< /Type /FontDescriptor
/FontName /ABCDEF+HelveticaNeue
/Flags 32
/FontFile2 19 0 R % ← the embedded TrueType program
/FontBBox [ -951 -481 1987 1077 ]
...
>>
endobj
/FontFile is Type 1, /FontFile2 is TrueType, /FontFile3 is CFF or OpenType. Condition 31-009 is a font used for visible text with none of the three.
Why this is an accessibility condition and not a print one
The intuitive objection is that this is about appearance, and appearance is not accessibility. The mechanism says otherwise.
A PDF paints glyphs by index. Turning an index back into a character requires the font’s own tables — its cmap, its glyph names, its ToUnicode CMap. When the font is embedded, those travel with the document and extraction is deterministic.
When it is not, the viewer substitutes a font it has locally. It maps the glyph indices through that font’s tables. For a Latin document with a common font the substitute is close enough that both rendering and extraction usually survive.
For Hebrew and Arabic they frequently do not. Substitution across fonts with different glyph orderings produces text that renders approximately and extracts as mojibake — and the extraction is what the screen reader gets. This is one of the reasons Hebrew PDFs fail in ways their authors never see.
It also interacts with 31-027: a font with no embedded program and no ToUnicode has nothing at all to map from.
How to check it free
pdffonts (Poppler, free) is the fastest:
$ pdffonts document.pdf
name type emb sub uni
------------------------ ------------ --- --- ---
ABCDEF+HelveticaNeue Type 1C yes yes yes
Arial TrueType no no no
no in the emb column is this condition.
Acrobat: File → Properties → Fonts tab. Embedded fonts say (Embedded Subset) or (Embedded). Anything without that annotation is not embedded.
veraPDF: reports clause 7.21.4.1 per font.
How to fix it free
There is no in-place fix worth trusting, and this is one of the few conditions where the honest answer is upstream only.
Re-export from the source. In Word: File → Options → Save → tick Embed fonts in the file, then export. In InDesign, fonts are embedded on export by default unless the licence forbids it — check the Advanced panel of the export dialog for a subsetting threshold. In LaTeX, pdflatex embeds by default; if a font is missing, the font package is not installed properly.
Acrobat’s Preflight has an Embed fonts fixup (Print Production → Preflight → PDF fixups). It works when the font is installed on your machine — Acrobat embeds the local copy. Two caveats: the local font may not be the one the document was made with, and the licence may not permit embedding. Check the result, do not assume it.
If the font is not available, the document cannot be fixed without re-typesetting it. That is a real answer, and it is better than a tool quietly substituting something.
Where Taggart differs
Taggart names every font and the pages it appears on:
/TaggartHebrew is used for rendering but its font program is not embedded. PDF/UA-1 requires every font used by visible text to be embedded.
The fix, embed-fonts, does one thing and refuses the rest. A file set in one of the fourteen standard fonts — Helvetica, Times, Courier, Symbol, ZapfDingbats — gets a program for it embedded, with the standard metrics, so the spacing on the page is unchanged; the change log says so and names where the programs come from (pdfium’s, under a BSD-style licence). In a viewer that had been substituting a different face, the letter shapes may differ slightly. For any other font it refuses, and says why:
Taggart has no program for Arial, TimesNewRoman. Re-export the source document with font embedding enabled, or install the fonts and re-distill. Substituting a font changes the rendered page and may not be licensed.
That refusal is the point. Every other fix in Taggart is safe because it edits the object model and leaves the content streams alone; substituting a font the file does not name is the one repair that would change what the page looks like. A tool that quietly swapped a font would break the guarantee everything else depends on — and it would do it invisibly, on exactly the documents where the substitute is furthest from the original.
How Taggart handles it
Taggart checks for this condition automatically and reports it as a blocker, with where in the file it found it.
The fix is Embed fonts. It changes what the document means, so Taggart proposes it and waits for your approval rather than applying it unattended.
Whatever Taggart changes, the page still looks identical. Fixes edit the PDF object model, not the content streams, and every remediation is re-rendered and compared against the original at structural similarity ≥ 0.999 before you get the file back. A tool that quietly reflows your document is worse than no tool.
Frequently asked questions
Why does embedding matter for accessibility rather than just for printing?
Because glyph-to-character mapping travels with the font. When a viewer substitutes a font it maps glyph indices through a different font's tables, so the text can render approximately right and extract completely wrong. For Latin text you usually get away with it. For Hebrew and Arabic you frequently do not.
Can Taggart embed the fonts for me?
For the fourteen standard fonts — Helvetica, Times, Courier, Symbol and ZapfDingbats in their styles — yes: their metrics are fixed by the PDF specification, so Taggart embeds a program with exactly those metrics and the spacing on the page does not move. For anything else, no, deliberately: it would mean substituting a font file that is not in the document, which changes the rendered page and may not be licensed. The fix names those fonts and tells you to re-export with embedding on.
What about the standard 14 fonts?
PDF/UA-1 has no exemption for them. Helvetica, Times and Courier must be embedded like anything else. Viewers substitute them reliably enough that the page looks right, which is why this failure survives so long unnoticed.
Does text render mode matter?
Yes. The requirement applies to fonts used by text intended to be rendered — a glyph counts as rendered when the text render mode is not 3, which is the invisible mode used for OCR layers. An invisible OCR layer does not need its font embedded.
Where this sits in the standards
| Standard | Reference |
|---|---|
| Matterhorn Protocol 1.1 | Checkpoint 31 (Fonts), index 31-009 |
| PDF/UA-1 (ISO 14289-1) | Clause 7.21.4.1-1 |
| WCAG 2.1 | 1.3.1 Info and Relationships — Level A |
| EN 301 549 / Section 508 / ADA Title II | All three point at WCAG 2.1 Level AA for non-web documents, so a Level A or AA criterion here is in scope for each of them. |
Related conditions
- 31-027 A font dictionary does not contain the ToUnicode entry and no exemption appliesA ToUnicode CMap is required unless the font uses MacRoman/MacExpert/WinAnsi encoding, or is a Type 1/Type 3 whose glyph names are all in the Adobe Glyph List or the Symbol set, or is a Type 0 whose descendant uses a standard Adobe character collection, or is a non-symbolic TrueType.
- 10-001 Character code cannot be mapped to UnicodeA glyph is painted whose character code has no Unicode equivalent reachable through the font's ToUnicode CMap, encoding, or glyph names. The text renders correctly but cannot be extracted.
- 31-011 The embedded font program does not contain glyphs for all referenced glyphsThe subset embedded in the file is missing glyphs the content stream asks for — very common when a document is edited after subsetting.
- 31-024 The Encoding entry is present in the font dictionary for a symbolic TrueType fontSymbolic TrueType fonts must not carry an /Encoding; the font's own cmap governs.
Other conditions in checkpoint 31
Checkpoint 31 covers fonts. These are its other failure conditions; the ones without a link are in the rule set but do not have a written page yet.
- 31-001 CIDSystemInfo Registry values are not identicalThe CMap and the descendant CID font must agree on the character collection registry.
- 31-002 CIDSystemInfo Ordering values are not identicalThe CMap and the descendant CID font must agree on the character collection ordering.
- 31-003 CIDSystemInfo Supplement of the CID font is lower than that of the CMapThe font's character collection supplement must be at least as new as the CMap's, or the CMap may reference CIDs the font does not define.
- 31-004 A Type 2 CID font contains neither a stream nor the name Identity as CIDToGIDMapCIDToGIDMap must be either the name /Identity or a stream mapping CIDs to glyph indices.
- 31-005 A Type 2 CID font does not contain a CIDToGIDMap entryThe entry is absent entirely.
- 31-006 A CMap is neither listed in ISO 32000-1 Table 118 nor embeddedA predefined CMap must be one of the standard names; anything else must be embedded in the file.
- 31-007 The WMode entry in a CMap dictionary is not identical to the WMode value in the CMap streamWriting mode (horizontal or vertical) must be declared consistently in the dictionary and the stream.
- 31-008 A CMap references another CMap which is not listed in ISO 32000-1 Table 118A UseCMap chain must terminate at a predefined CMap.
- 31-010 A font program is embedded that is not legally embeddable for unlimited, universal renderingThe font's embedding permission bits forbid the kind of embedding used. Machines can read the flags but the flags may not reflect the actual licence.
- 31-011 The embedded font program does not contain glyphs for all referenced glyphsThe subset embedded in the file is missing glyphs the content stream asks for — very common when a document is edited after subsetting.
- 31-012 A glyph present in an embedded Type 1 font program is not listed in CharSetCharSet must accurately list the glyphs in the embedded subset.
- 31-013 A glyph listed in CharSet is not present in the Type 1 font programCharSet promises glyphs the font does not contain.
- 31-014 A glyph present in an embedded CID font program is not listed in CIDSetCIDSet must accurately list the CIDs in the embedded subset.
- 31-015 A glyph listed in CIDSet is not present in the CID font programCIDSet promises CIDs the font does not contain.
- 31-016 Glyph widths in the font dictionary and the font program differThe /Widths array must agree with the embedded font program.
- 31-017 A non-symbolic TrueType font has no non-symbolic cmapA font declared non-symbolic must actually carry a (3,1) or (1,0) cmap subtable.
- 31-018 A glyph cannot be looked up by any non-symbolic cmap entrySome rendered glyph is unreachable through the declared cmap tables.
- 31-019 The font dictionary for a non-symbolic TrueType font does not contain an Encoding entryNon-symbolic TrueType fonts must declare an /Encoding.
- 31-020 The Encoding dictionary for a non-symbolic TrueType font does not contain BaseEncodingIf /Encoding is a dictionary it must name a /BaseEncoding.
- 31-021 BaseEncoding is neither MacRomanEncoding nor WinAnsiEncodingOnly MacRomanEncoding and WinAnsiEncoding are permitted for non-symbolic TrueType fonts.
- 31-022 Differences contains glyph names not listed in the Adobe Glyph ListGlyph names in /Differences must be resolvable through the Adobe Glyph List so a processor can derive Unicode.
- 31-023 Differences present but the font has no (3,1) Microsoft Unicode cmapThe Differences array is resolved through the (3,1) cmap; without it the mapping is undefined.
- 31-024 The Encoding entry is present in the font dictionary for a symbolic TrueType fontSymbolic TrueType fonts must not carry an /Encoding; the font's own cmap governs.
- 31-025 The embedded font program for a symbolic TrueType font contains no cmapA symbolic TrueType font must contain at least one cmap subtable.
- 31-026 A symbolic TrueType font has multiple cmaps but none is a (3,0) Microsoft Symbol cmapWith multiple cmaps present, a (3,0) symbol cmap is required to disambiguate.
- 31-027 A font dictionary does not contain the ToUnicode entry and no exemption appliesA ToUnicode CMap is required unless the font uses MacRoman/MacExpert/WinAnsi encoding, or is a Type 1/Type 3 whose glyph names are all in the Adobe Glyph List or the Symbol set, or is a Type 0 whose descendant uses a standard Adobe character collection, or is a non-symbolic TrueType.
- 31-028 Unicode values in the ToUnicode CMap are zeroU+0000 is not a valid mapping target; it usually means the producer could not determine the character and wrote a placeholder.
- 31-029 Unicode values in the ToUnicode CMap are U+FEFF or U+FFFEByte-order marks are not characters and must not appear as mapping targets.
- 31-030 Characters used in text showing operators reference the .notdef glyphThe content stream paints glyph index 0, which is by definition "no glyph" — typically a hollow box or nothing at all.
Check your own file. Taggart’s validator is free and unlimited — 75 of the 87 Matterhorn conditions software can decide, with the other 12 listed for you to confirm; no watermark, no expiry, and no account needed up to 60 pages.
Verified against a real document on . Last updated .