Skip to content

fix(font): name subset fonts with a tag, escape font names - #48

Closed
serpentblade wants to merge 1 commit into
dskripchenko:mainfrom
One-Learning-Community:fix/font-subset-tag
Closed

serpentblade wants to merge 1 commit into
dskripchenko:mainfrom
One-Learning-Community:fix/font-subset-tag

Conversation

@serpentblade

Copy link
Copy Markdown
Contributor

Embedded TrueType subsets were named after the whole font (/BaseFont /Inter-Bold). ISO 32000-1 §9.6.4 requires a subset's /BaseFont and /FontName to start with a six-letter tag, e.g. DCFUHW+Inter-Bold. Without it, two subsets of one font in a document share a name, and tools that look fonts up by name (Ghostscript, preflight, merging) can mix them up.

  • The tag is a hash of the subset's bytes, so different subsets get different tags and the output stays reproducible.
  • Fonts embedded whole and CFF fonts keep the plain name.
  • PostScript names are now escaped as PDF names (§7.3.5).

Tests added; full suite and phpstan pass. Checked with pdffonts and qpdf --check.

🤖 Generated with Claude Code

An embedded TrueType subset was named after the whole font: /BaseFont
/Inter-Bold. ISO 32000-1 §9.6.4 requires a subset's name — both /BaseFont
entries and the descriptor's /FontName — to start with six uppercase
letters and a plus sign: /BaseFont /DCFUHW+Inter-Bold.

Without the tag, two subsets of one font in a document share a name. A
certificate set in Inter used it for bold and for bold italic, so it
carried two different Inter-Bold subsets under one name; a processor that
looks fonts up by name (Ghostscript, preflight, merging) can draw one
subset's text from the other and lose glyphs. Tools also took the subset
for the whole font: pdffonts listed it with sub "no".

The tag is taken from a hash of the subset's bytes, so different subsets
get different tags and the same subset always gets the same one — the
output stays reproducible. Fonts embedded whole (subset: false) and CFF
fonts, which are never subset, keep the plain name.

The PostScript name was also written into the PDF name unescaped. The
OpenType spec keeps delimiters, '#' and non-printable bytes out of it, but
a font that broke the rule produced a broken font dictionary; those
characters are written as #xx now (§7.3.5).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dskripchenko added a commit that referenced this pull request Oct 27, 2026
Subset font tags and escaped names (from #48), with CIDSet for PDF/A-1
@dskripchenko

Copy link
Copy Markdown
Owner

Thank you, @serpentblade — subset tags as ISO 32000 asks, deterministic from the subset's bytes, plus proper name escaping: exactly right.

Your commit is merged unchanged, with your authorship, through #50. We meant to push the follow-up straight into this branch, but GitHub refused it for a fork owned by an organisation, so we carried it over to a branch here.

What we added, and why:

  • /CIDSet for TrueType subsets. Once subsets carry the ABCDEF+ tag, veraPDF treats them as subsets and applies ISO 19005-1 §6.3.5, which requires a /CIDSet for a CIDFont subset. The library wrote none, so pdfa-1b and pdfa-1a in our conformance workflow failed rule 6.3.5-3. They pass on main only because subsets were untagged. CI doesn't run automatically on pull requests from forks, so you couldn't have seen it.
    The set marks every glyph below numGlyphs. Our subsetter keeps glyph numbering and leaves unused glyphs empty, and veraPDF counts each of them. A narrower set fails PDF/A-2/3 on rule 6.2.11.4.2-2.
  • CHANGELOG [Unreleased] → Fixed, including the visible change of embedded subset names.

A small request for next time: please open pull requests from a fork under your personal account with "Allow edits by maintainers" ticked. GitHub honours that setting for personal forks, and we can then push small fixes straight into your branch.

Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants