Matterhorn 31-020 · PDF/UA-1 UA1:7.21.6-4
No BaseEncoding in a TrueType font's Encoding dictionary
If /Encoding is a dictionary it must name a /BaseEncoding.
The condition, as the protocol states it. “The font dictionary for a non-symbolic TrueType font contains an Encoding dictionary which does not contain a BaseEncoding entry.”
Matterhorn Protocol 1.1, checkpoint 31, index 31-020, section UA1:7.21.6-4. Software can decide this one on its own.
What a screen reader actually does
Character codes cannot be reliably mapped to characters.
What the dictionary looks like
A simple font maps one byte in the content stream to one glyph. For a TrueType font that is not marked symbolic, the byte goes through a 256-entry table of glyph names first, and the font’s /Encoding entry says how to build that table. It can be a name, /WinAnsiEncoding for instance, or a dictionary that starts from a named encoding and overrides some codes:
12 0 obj
<< /Type /Font
/Subtype /TrueType
/BaseFont /ABCDEF+SourceSans
/FontDescriptor 13 0 R % /Flags 32: Nonsymbolic
/Encoding << /Type /Encoding
/Differences [ 128 /Euro 146 /quoteright ]
>> % ← no /BaseEncoding
>>
endobj
The /Differences array says code 128 is the Euro sign and code 146 a closing quote. It does not say what the other 254 codes are. That is what /BaseEncoding is for, and condition 31-020 is an encoding dictionary without it.
What fills the gap
ISO 32000-1 answers the question, but not in a way anyone should rely on. For a non-symbolic TrueType font, the viewer starts the table from /BaseEncoding, applies the differences, and fills whatever is still empty from StandardEncoding, the old Adobe Latin encoding. StandardEncoding is not WinAnsi. Of the 224 codes from 32 to 255, the two disagree on 117:
| Code | WinAnsiEncoding | StandardEncoding |
|---|---|---|
0x27 | ' straight apostrophe | ’ closing quote |
0x60 | ` backtick | ‘ opening quote |
0x92–0x94 | ’ “ ” | nothing (.notdef) |
0xE9 | é | Ø |
A producer that leaves /BaseEncoding out almost always means WinAnsi, and many viewers assume WinAnsi. A viewer that follows the specification to the letter does not. The byte 0xE9 is then é in one viewer and Ø in the other — or a missing glyph, if the subset has no Ø — and the curly quotes at 0x92 to 0x94, which StandardEncoding does not define, draw nothing.
PDF/UA-1 closes the question. Clause 7.21.6 requires every non-symbolic TrueType font to name MacRomanEncoding or WinAnsiEncoding, either as its /Encoding or as the /BaseEncoding of its encoding dictionary. A font that names nothing is 31-019; one that names something else is 31-021; this is the dictionary that names nothing.
What the user hears
PDF/UA exempts non-symbolic TrueType fonts from needing a ToUnicode CMap, on the grounds that their encoding already says what every code means. So for extraction, this table is often the only route from a byte to a character. A screen reader working from a file like the one above gets whatever its PDF library decided the empty slots were. Usually that is WinAnsi and the text reads correctly. Sometimes it is StandardEncoding, and the reader announces Ø in the middle of a French word, or nothing where an apostrophe was.
If the font also carries a ToUnicode CMap, readers use that first and extraction survives. The drawing problem does not go away, and the font still fails the condition.
Where it comes from
For a Type 1 font, an encoding dictionary without a base is ordinary: leaving it out means “the encoding built into the font program”, and a Type 1 program has one. A TrueType program has no single built-in encoding of that kind, so the same omission on a TrueType font leaves the meaning to each viewer. A generator that writes a /Differences array for the handful of characters it remaps, typically the Euro sign, curly quotes and ligatures, and considers everything else obviously WinAnsi, produces exactly this dictionary.
How to check it free
pdffonts (Poppler) will not tell you directly. Its encoding column shows Custom for any font with a Differences array, whether or not a base is named. It is still the quickest way to find the candidates and their object numbers:
$ pdffonts report.pdf
name type encoding emb sub uni object ID
------------------------ --------- ---------- --- --- --- ---------
ABCDEF+SourceSans TrueType Custom yes yes no 12 0
qpdf (free) prints the dictionary itself. qpdf --show-object=12 report.pdf shows the font; if /Encoding is a reference, show that object too, and look for /BaseEncoding.
Acrobat Pro can show the same dictionary without editing it. Adobe’s guide to advanced preflight inspections gives the route: All tools → Use print production → Preflight, then in the Preflight dialog Options → Browse Internal PDF Structure. Expand the tree from the catalog down to the page’s font resources and open the font’s Encoding entry. Adobe notes that you cannot edit the PDF in that window.
veraPDF tests the WinAnsi-or-MacRoman requirement for non-symbolic TrueType fonts in its PDF/UA-1 profile.
How to fix it free
Add the base yourself. This is one of the few font conditions with a small, safe hand edit, as long as you check what it touches. With qpdf:
qpdf --qdf --object-streams=disable report.pdf edit.pdf
# in a text editor that preserves binary data, add
# /BaseEncoding /WinAnsiEncoding
# inside the font's Encoding dictionary
fix-qdf edit.pdf fixed.pdf
If every code the text uses is either in the Differences array or a plain letter, digit or ASCII punctuation mark other than ' and `, the edit changes nothing any viewer draws, because WinAnsi and StandardEncoding agree on all of those. If the text uses codes above 127, compare the page before and after in more than one viewer.
Or re-export. Adobe’s guidance for the Accessibility Checker’s Character encoding rule, in Create and verify PDF accessibility, is to change the font in the source document, preferably to an OpenType font, and re-create the PDF. Adobe also says some character-encoding problems are not repairable within Acrobat, and this looks like one of them: Adobe documents no way to edit a font’s encoding dictionary in Acrobat.
What Taggart reports
One finding per font, with the font’s object number and the first page it appears on:
/ABCDEF+SourceSans is a non-symbolic TrueType font whose /Encoding dictionary has no /BaseEncoding entry.
Taggart decides “non-symbolic” from the font descriptor’s /Flags: the Nonsymbolic bit set, or the Symbolic bit clear. A font whose descriptor carries no flags at all is not held to this condition. It does not also report 31-021 for the same font, because there is no encoding name to be the wrong one, and it does not report a missing ToUnicode CMap, because this font type is exempt from needing one.
There is no repair. Adding the base is a one-line edit, but on a file whose text uses the codes where the two encodings disagree it changes what some viewers draw, and Taggart does not make edits that change the page.
How Taggart handles it
Taggart checks for this condition automatically and reports it as a blocker, with where in the file it found it.
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
Does a missing BaseEncoding change what the page looks like?
It can, and that is the problem. ISO 32000-1 fills every code the Differences array does not mention from StandardEncoding, which disagrees with WinAnsi on the straight apostrophe, the backtick and most of the upper half of the table. A viewer that assumes WinAnsi draws something else. Which one you get depends on the viewer.
Is this the same as 31-019?
No. 31-019 is a non-symbolic TrueType font with no /Encoding at all. This one has an encoding dictionary, usually carrying a Differences array, that never names the encoding the differences are from.
Can I just add /BaseEncoding /WinAnsiEncoding?
Usually, and it is the fix. It changes nothing for codes the Differences array covers, or for letters, digits and the ordinary ASCII punctuation, because StandardEncoding and WinAnsi agree on those. Check the apostrophe, the backtick and anything above 127 before you trust it.
Why doesn't Taggart add it?
Because for codes outside those ranges the edit can change which glyph a viewer draws, and Taggart's repairs do not change the rendered page. It reports the font and leaves the edit to you or to a re-export.
Where this sits in the standards
| Standard | Reference |
|---|---|
| Matterhorn Protocol 1.1 | Checkpoint 31 (Fonts), index 31-020 |
| PDF/UA-1 (ISO 14289-1) | Clause 7.21.6-4 |
| 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-019 The font dictionary for a non-symbolic TrueType font does not contain an Encoding entryNon-symbolic TrueType fonts must declare an /Encoding.
- 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.
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-009 For a font used by text intended to be rendered the font program is not embeddedPDF/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.
- 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-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.
Checked with Taggart on a generated file that fails this condition on . The Acrobat steps follow Adobe’s documentation and were not walked through by hand. Last updated .