Matterhorn 31-012 · PDF/UA-1 UA1:7.21.4.2-1
Type 1 CharSet that leaves out glyphs the font has
CharSet must accurately list the glyphs in the embedded subset.
The condition, as the protocol states it. “The FontDescriptor dictionary of an embedded Type 1 font contains a CharSet string, but at least one of the glyphs present in the font program is not listed in the CharSet string.”
Matterhorn Protocol 1.1, checkpoint 31, index 31-012, section UA1:7.21.4.2-1. Software can decide this one on its own.
What a screen reader actually does
Processors may mis-handle the subset.
What CharSet is
/CharSet is an optional entry in the font descriptor of a Type 1 font: a string of glyph names, each written as a PDF name, listing what the embedded subset contains. .notdef is left out, because every font has it.
PDF/UA-1 does not require the entry, but if it is there it has to be true. It must name every glyph present in the font program, whether the document uses that glyph or not. This condition is a CharSet that leaves one out; the opposite failure, a CharSet naming a glyph the program does not have, is 31-013.
The file Taggart’s test suite uses for this page has a Type 1 font embedded as CFF, with four glyphs:
<< /Type /FontDescriptor
/FontName /JBATCH+CharSetShort
/Flags 32
/FontFile3 9 0 R % /Subtype /Type1C — glyphs .notdef, A, B, C
/CharSet (/A/B) % C is in the program and not in the list
>>
The page shows AB. C is never drawn, and that is beside the point: it is in the program, so it belongs in the list.
Why the entry exists, and who reads it
CharSet lets a processor know what a subset can draw without opening the font program. PDF/A-1 made it mandatory for Type 1 subsets, which is why so many files carry one. PDF/UA-1 only asks that, where it exists, it agrees with the program — a description that may be wrong is worse than none, because the software reading it has no way to tell.
What a screen-reader user hears
Nothing different. Drawing goes to the font program and reading goes to the encoding or the ToUnicode CMap; neither looks at CharSet. The test file renders and copies as AB with the entry wrong, and would with it right.
That is worth saying plainly, because the condition is reported as a blocker and it is easy to assume a blocker means a reader is losing something. Here the reader is not. The file is non-conformant because it misdescribes its own font, and the cost of that falls on software that believes the description.
Where it comes from
Glyphs that come along with other glyphs. A Type 1 font can draw an accented letter by combining a base letter with an accent, so a subset containing é may also have to contain e and acute. A producer that writes CharSet from the characters it set, rather than from the program it actually embedded, leaves the components out.
A program replaced without its descriptor. A tool that re-subsets or swaps the embedded font program and copies the old descriptor across can leave a CharSet describing a different subset, missing glyphs in one direction or the other.
Hand-edited font dictionaries, where the list and the program were never compared at all.
How to check it free
veraPDF tests it under clause 7.21.4.2. Its rule applies only to fonts whose name carries a subset tag — six capital letters and a plus sign, as in ABCDEF+Garamond — so a full font with an inaccurate CharSet passes veraPDF on this point.
Acrobat Pro can show both halves. Following Adobe’s guide to advanced preflight inspections, select Use print production → Preflight from the All tools menu, then Options → Browse Internal PDF Structure, and find the font descriptor: its CharSet string is there. Then, from the same Options menu, Create Inventory — Adobe says the inventory shows the glyphs in each font. A glyph in the inventory that is not in the string is this condition.
How to fix it free
Delete the entry. It is optional, and the requirement only applies when it is present, so removing it resolves the condition without touching anything that draws or reads text. Acrobat cannot do this — Adobe’s structure browser lets you look at font objects but not edit them — but a short script with the free Python library pikepdf can:
import pikepdf
with pikepdf.open("in.pdf") as pdf:
for obj in pdf.objects:
if isinstance(obj, pikepdf.Dictionary) and obj.get("/Type") == "/FontDescriptor":
if "/CharSet" in obj:
del obj["/CharSet"]
pdf.save("out.pdf")
Unless the file also claims PDF/A-1. PDF/A-1 requires CharSet on every Type 1 subset, so deleting it trades one failure for another. Check the document’s XMP metadata for a pdfaid:part of 1; if it is there, rebuild the string from the glyph names in the program instead, or re-export.
Re-export from the source, if the producer is one that writes CharSet correctly. If the same producer wrote this one, it will write the same thing again.
What Taggart does
Taggart does not detect this condition, because it does not open embedded font programs. On the test file — an embedded Type 1 font whose CharSet leaves out a glyph — it reports nothing about the font. The condition is instead on Taggart’s list of those it does not check, and no PDF/UA claim is made or written into the file until a person confirms that list.
What it reports under 31-012 is a narrower case it can decide from the dictionaries alone: a font descriptor with a CharSet and no embedded program for it to describe.
/JBATCH+CharSetShort declares a /CharSet string but has no embedded font program to describe.
That font is reported under 31-009 as well, and 31-009 is the one to act on: once the font is embedded, the CharSet has something to be compared with. Taggart applies that narrower check to any font with a CharSet, with or without a subset tag. For the condition this page is about, use veraPDF or the inventory comparison above before you confirm it.
How Taggart handles it
Software could decide this one, and Taggart does not check it yet. A clean report from Taggart says nothing about it either way. It is on the list of conditions Taggart asks you to confirm before it writes the PDF/UA claim into the file; check it by hand or with another validator, as described above.
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 an incomplete CharSet change what a screen reader reads?
No. Neither drawing nor extracting text consults CharSet: the viewer reads glyphs from the font program and characters from the encoding or ToUnicode CMap. The condition is about the file describing itself accurately, and its cost falls on software that trusts the description.
Is it safe to delete the CharSet entry?
For PDF/UA, yes: the entry is optional, and the requirement only applies when it is present. PDF 2.0 deprecates it. The exception is a file that also claims PDF/A-1, which requires CharSet on every Type 1 subset; there, rebuild the list rather than removing it.
Why would a subset contain glyphs no text uses?
Because some glyphs are built from others. A Type 1 accented letter can be drawn by combining a base letter and an accent, and those two have to travel with it, so the subsetter keeps them. A producer that writes CharSet from the characters on the page, rather than from the program it embedded, leaves them out.
Does this apply to TrueType or CID fonts?
No. CharSet is meaningful only for Type 1 fonts, including Type 1 fonts embedded in compact form as CFF. A CID font describes its subset with a CIDSet bitmap instead, and the same rule in that form is condition 31-014.
Where this sits in the standards
| Standard | Reference |
|---|---|
| Matterhorn Protocol 1.1 | Checkpoint 31 (Fonts), index 31-012 |
| PDF/UA-1 (ISO 14289-1) | Clause 7.21.4.2-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-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-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-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.
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-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 does not check this condition yet, and lists it for you to confirm. Its validator is free and checks 75 of the 87 Matterhorn conditions software can decide — no watermark, no expiry, and no account needed up to 60 pages.
Taggart does not check this condition yet. A generated file that fails it is in the repository, with a test that fails the day Taggart starts catching it. Written on . The Acrobat steps follow Adobe’s documentation and were not walked through by hand. Last updated .