Matterhorn 31-020 · PDF/UA-1 UA1:7.21.6-4

No BaseEncoding in a TrueType font's Encoding dictionary

BlockerCheckpoint 31: FontsWCAG 1.3.1 (A)

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:

CodeWinAnsiEncodingStandardEncoding
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

Standards this condition maps to
StandardReference
Matterhorn Protocol 1.1Checkpoint 31 (Fonts), index 31-020
PDF/UA-1 (ISO 14289-1)Clause 7.21.6-4
WCAG 2.11.3.1 Info and Relationships — Level A
EN 301 549 / Section 508 / ADA Title IIAll 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.

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.

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.

Check a PDF free

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 .