fix: resolve core-14 font aliases to their standard metrics#294
Conversation
A PDF may reference a standard Type1 font by a common family alias such as Arial or Times New Roman and legally omit the /Widths table. The width resolver only matched when a canonical PostScript name (Helvetica, Times-Roman, ...) was a substring of the font name, so these aliases missed every bundled AFM and fell back to a flat 500 units/em. At 10pt that advances every glyph 5.00pt instead of the real width, leaving word bounding boxes about 20 percent too narrow and drifting progressively left in long strings. Bind the common Arial, Times New Roman and Courier New aliases to the core-14 metrics that PDF viewers substitute, so their advances come from the real Helvetica, Times and Courier AFM data. Fonts with an explicit /Widths table, and names that already contain a canonical family, keep their existing behavior. Signed-off-by: pablopupo <145598901+pablopupo@users.noreply.github.com>
|
✅ DCO Check Passed Thanks @pablopupo, all your commits are properly signed off. 🎉 |
Merge Protections🟢 Merge protection satisfied — ready to merge. Show 1 satisfied protection🟢 Enforce conventional commitMake sure that we follow https://www.conventionalcommits.org/en/v1.0.0/
|
|
@pablopupo I have resolved already quite a few issues regarding this with the latest renderer. Can you attach here a PDF that does not work on main but that this PR solves? |
|
This is a small PDF that still breaks on current main, for example. It is one page with the same line of text three times, once each in Arial, TimesNewRoman and Courier New, none of them carrying a /Widths table. On main every glyph in the Arial and Times lines advances a flat 6.0pt at 12pt, so both lines come out 210.0pt wide. With this PR cherry-picked onto main (it applies cleanly) the same lines measure 162.64pt and 165.02pt, which matches the bundled Helvetica and Times AFM widths glyph for glyph, from 2.66pt for i and l up to 11.33pt for W. The CourierNew line is 252.0pt in both builds because courier already matches as a substring of the name, so what is left after your renderer work is the Arial and Times style aliases falling through to the 500 fallback. https://github.com/pablopupo/docling-parse/raw/repro-294/core14-alias-no-widths.pdf |
|
Before
after
Groundtruth
@pablopupo I am not 100% convinced we solved the entire problem. Definitely going in the right direction |
|
OK, I fixed the rendering here: #298 |
|
Thanks for jumping on the renderer half so quickly! That matches what your screenshots showed, the advances were already right and the preview just needed the face resolution. I built #298 locally and re-ran my repro, the geometry comes out byte for byte identical to this branch (162.64 / 165.02 / 252.0, matching the AFMs) and all three lines paint with the right faces now, even with the MS fonts hidden so the alias fallback actually gets exercised. Since #298 includes my commit unchanged, would you be open to merging this one first and then rebasing #298 so it's just the renderer commit on top? That keeps the authorship clean in the history, and it would also be my first PR in this repo. If that's a pain to sequence, no worries at all! Thank you! |
|
@pablopupo Yes, I will merge this first (will fix the merge conflicts in case), I understand you ant credit, which you deserve. One small ask: can you make an extended pdf (similar to https://github.com/pablopupo/docling-parse/raw/repro-294/core14-alias-no-widths.pdf) that has "all" the different fonts, and attach it in a comment on #298 ? I want to include that into our regression tests. |
PeterStaar-IBM
left a comment
There was a problem hiding this comment.
looks good (and thanks for flagging this issue!)



Standard Type1 fonts can be referenced by a common family alias like Arial or Times New Roman and legally ship without a /Widths table. docling-parse only found the bundled metrics when a canonical PostScript name (Helvetica, Times-Roman and so on) was a substring of the font name, so those aliases matched nothing and every glyph fell back to a flat 500 units/em. At 10pt that advances each character 5.00pt instead of its real width, which leaves word bounding boxes off and drifting further along the line the longer the string. On a 92 character Arial line the last glyph lands about 71pt away from where it should.
This is the remaining piece of #180. The canonical base-14 names from that report already resolve on current main (Courier gives the correct 6.00pt, Helvetica and Times-Roman give their real varying widths), so the change binds the Arial, Times New Roman and Courier New aliases to the Core-14 metrics that PDF viewers substitute. Arial now matches Helvetica glyph for glyph (A 6.67, W 9.44, i 2.22, m 8.33 at 10pt) instead of a flat 5.00. Fonts with an explicit /Widths table and names that already contain a canonical family keep their existing behavior, and a bundled real metric like ArialMT still wins over the alias. No new font data is added, the aliases reuse the Core-14 AFM files already shipped in pdf_resources.
Added tests/test_standard_font_widths.py, which builds its minimal PDFs in memory so it needs no external data. It covers Courier at 6.00pt, a proportional font with varying non-500 widths, the alias resolution for Arial and Times, and an explicit /Widths table taking precedence. The full test suite passes locally (81 passed).