Skip to content

Draw a stand-in for a font the file does not carry - #9

Merged
tannevaled merged 1 commit into
mainfrom
substitute-fonts
Aug 25, 2026
Merged

Draw a stand-in for a font the file does not carry#9
tannevaled merged 1 commit into
mainfrom
substitute-fonts

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

A PDF need not carry the font its text is set in. Fourteen faces — four weights each of Helvetica, Times and Courier, plus Symbol and ZapfDingbats — every reader is expected to have of its own; and in practice a file names any font at all and hopes.

I counted. Of the 95 818 corpus pages that show text:

name a font the file does not carry 40 437 (42.2%)
carry no font whatever 38 663
unembedded fonts, total 113 140
…of those, with no /Widths either 39 431

Drawing nothing for those is two pages in five with no text on them.

What it draws instead

Arimo, Tinos and Cousine are metric-compatible with Helvetica, Times and Courier — the same advances, glyph for glyph — so a stand-in gives the text the width it was meant to have even where the document gives no widths of its own, which one of the standard fourteen never does. (Tinos was not bundled until fonts#10; HasWidth is pdffont#2.)

For any other name, the descriptor's flags say whether it wanted a serif, a sans or a typewriter.

Only one weight of each is carried, so a bold is drawn by stroking the outline as well as filling it and an italic by leaning it over — a faux bold and a faux italic, which is what every reader does with a face it has not got in the weight asked for.

What it leaves alone

Symbol, the dingbats, composite fonts and Type 3 fonts. A composite font is addressed by glyph number and a stand-in's numbers are its own, so drawing one would put arbitrary letters on the page; and no face here carries Symbol's glyphs. Something is not better than nothing when the something is the wrong alphabet.

Measured

334 of 4 057 pages changed, 333 of them gaining ink — and this sample is arXiv figures; a corpus of documents would show far more. The one page that lost any lost 0.17% of a very inky page. Robustness unchanged: 4 108 pages, no panics, six blank.

What this cannot do is invent a font's shapes. A page set in a face nobody has is a page set in something else, and it says so nowhere — which is what every reader does, and better than a blank page by the width of the text on it.

100% statement coverage.

A PDF need not carry the font its text is set in. Fourteen faces every reader
is expected to have of its own, and in practice a file names any font at all
and hopes.

Of the 95 818 corpus pages that show text, 40 437 name a font the file does
not carry and 38 663 carry none whatever. Drawing nothing for those is two
pages in five with no text on them.

Arimo, Tinos and Cousine are metric-compatible with Helvetica, Times and
Courier — the same advances, glyph for glyph — so a stand-in gives the text
the width it was meant to have even where the document gives no widths of its
own, which one of the standard fourteen never does. For any other name the
descriptor's flags say whether it wanted a serif, a sans or a typewriter.

Only one weight of each is carried, so a bold is drawn by stroking the outline
as well as filling it and an italic by leaning it over — what a typesetter
calls a faux bold and a faux italic, and what every reader does with a face it
has not got in the weight asked for.

Symbol, the dingbats, composite fonts and Type 3 fonts are left alone. A
composite font is addressed by glyph number and a stand-in's numbers are its
own, so drawing one would put arbitrary letters on the page; and no face here
carries Symbol's glyphs. Something is not better than nothing when the
something is the wrong alphabet.

Measured on the sample by hashing every page's pixels: 334 of 4 057 changed,
333 of them gaining ink. What this cannot do is invent a font's shapes: a page
set in a face nobody has is a page set in something else, and it says so
nowhere — which is what every reader does, and better than a blank page by the
width of the text on it.
@tannevaled
tannevaled merged commit accb471 into main Aug 25, 2026
1 check passed
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.

1 participant