GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — pdf: Improve text with characters outside embedded font limits by QuLogic · Pull Request #30512 · matplotlib/matplotlib

Conversation

@QuLogic

@QuLogic QuLogic commented Sep 4, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

PR summary

For character codes outside the embedded font limits (256 for type 3 and 65536 for type 42), we output them as XObjects instead of using text commands. But there is nothing in the PDF spec that requires any specific encoding like this.

Since we now support subsetting all fonts before embedding, split each font into groups based on the maximum character code (e.g., 256-entry groups for type 3), then switch text strings to a different font subset and re-map character codes to it when necessary.

This means all text is true text (albeit with some strange encoding), and we no longer need any XObjects for glyphs. For users of non-English text, this means it will become selectable and copyable again.

There are 3 steps to achieve this change:

  1. Track both character codes and glyphs in CharacterTracker. This class takes care of splitting characters into subsets that fit the desired PDF font type limits. -> moved to pdf/ps: Track full character map in CharacterTracker #30566
  2. Output each used font block as a separate subsetted font. Also change the subset prefix to use the glyph indices, which are unique, unlike the character codes. -> first commit here
  3. Generate a ToUnicode dictionary for the subset font. We already did this for type 42 fonts, but the implementation was incorrect as it didn't correctly handle non-BMP characters. For type 3, support was added in PDF 1.2, but we produce 1.4; there is a fallback to the glyph names, but it is inconsistent and probably depends on the original font having the right names. -> second commit here

In the future, we may wish to extend the implementation in CharacterTracker to "compress" the character map it produces (i.e., if you use 255 characters all from a different 256-sized block with type 3, you get 255 fonts, but we could compress that to a single font.) I tried to avoid hard-coding any assumptions that the mapping is block-by-block, but it is possible that something slipped through, so I do not want to spend too much time on that right now.

Formerly, with multi_font_type3.pdf (after adding the emoji to the test), copying the text in evince would produce:

There are basic characters
ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz
0123456789 !”#$%&’()*+,-./:;¡=¿?@[“]ˆ˙‘—–˝˜
and accented characters
ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß
àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
in between!

and with multi_font_type42.pdf:

There are basic characters
ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz
0123456789 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
and accented characters
ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß
àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğ
ĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿ
ŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞş
ŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ
ƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟ
ƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿ
ǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟ
ǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿ
ȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ
ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿ
ɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏ
in between!

and now we get for both type 3 and 42:

There are basic characters
ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz
0123456789 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
and accented characters
ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß
àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğ
ĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿ
ŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞş
ŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ
ƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟ
ƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿ
ǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟ
ǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿ
ȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ
ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿ
ɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏ😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏
in between!

Note how in the third line for type 3:

  1. the quotes are 'curly' instead of straight quotes
  2. the chevrons <> are inverted exclamation/question marks ¡¿
  3. the backslash \ is a curly opening double quote “
  4. the caret ^, underscore _, and tilde ~ are {circumflex, dot, tilde} accents/smaller glyphs ˆ˙˜
  5. the braces {} are em-dash and curly quotes —˝
  6. the pipe | is en-dash –
    Everything from the seventh to second-last line is missing in type 3 since it's outside of the 256 limit, and all the emoji are missing from type 42 since that's outside the 65536 limit.

This depends on #30520, #30335, #30566, and #30567.

PR checklist

  • "closes #0000" is in the body of the PR description to link the related issue
  • new and changed code is tested
  • [n/a] Plotting related features are demonstrated in an example
  • New Features and API Changes are noted with a directive and release note
  • Documentation complies with general and docstring guidelines

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

anntzer reacted with hooray emoji
All reactions
  • 🎉 1 reaction
@QuLogic QuLogic added this to the v3.11.0 milestone Sep 4, 2025
@QuLogic QuLogic added this to Font and text overhaul Sep 4, 2025
@QuLogic QuLogic added the status: waiting for other PR label Sep 4, 2025
@github-project-automation github-project-automation Bot moved this to Waiting for other PR in Font and text overhaul Sep 4, 2025
@github-actions github-actions Bot added topic: text backend: ps backend: pdf backend: svg backend: cairo topic: text/mathtext labels Sep 4, 2025
@QuLogic
QuLogic force-pushed the pdf-text-subsets branch from 7ffffb5 to 3fc92f4 Compare September 4, 2025 06:06
@QuLogic QuLogic mentioned this pull request Sep 4, 2025
TST: Remove redundant font tests #30513
Merged
1 task done
@anntzer

anntzer commented Sep 4, 2025

Copy link
Copy Markdown
Contributor

This is great and would also allow getting rid of _get_pdf_charprocs. I'll try to have a look at #30335 to start...

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@QuLogic QuLogic mentioned this pull request Sep 4, 2025
Use glyph indices for font tracking in vector formats #30335
Merged
1 task done
@anntzer

anntzer commented Sep 5, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

The first two commits (the loop merge and the Type3 encoding change) seem independent from the rest (even from the switch to glyph index tracking) and could be merged first via a separate PR? (I can probably approve them right away.)
I still need to properly review the next one (charmap tracking) but that can also come next by itself?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@QuLogic QuLogic mentioned this pull request Sep 6, 2025
pdf: Simplify Type 3 font character encoding #30520
Merged
1 task done
@QuLogic

QuLogic commented Sep 6, 2025

Copy link
Copy Markdown
Member Author

I split the type3 encoding to #30520, but the loop merge has conflicts with the glyph index change.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@github-actions github-actions Bot added the status: needs rebase label Sep 8, 2025
@QuLogic
QuLogic force-pushed the pdf-text-subsets branch from 3fc92f4 to 275fb16 Compare September 16, 2025 05:46
@github-actions github-actions Bot removed the status: needs rebase label Sep 16, 2025
anntzer
anntzer reviewed Sep 16, 2025
View reviewed changes
Comment thread lib/matplotlib/backends/_backend_pdf_ps.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

anntzer
anntzer reviewed Sep 16, 2025
View reviewed changes
Comment thread lib/matplotlib/backends/_backend_pdf_ps.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Sep 16, 2025
pdf/ps: Track full character map in CharacterTracker #30566
Merged
pdf: Merge loops for single byte text chunk output #30567
Merged
@QuLogic
QuLogic force-pushed the pdf-text-subsets branch from 275fb16 to 60f3a4f Compare September 16, 2025 06:59
@QuLogic

QuLogic commented Sep 16, 2025

Copy link
Copy Markdown
Member Author

The first two commits (the loop merge and the Type3 encoding change) seem independent from the rest (even from the switch to glyph index tracking) and could be merged first via a separate PR? (I can probably approve them right away.)

Split the loop merge as well.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

anntzer
anntzer reviewed Sep 16, 2025
View reviewed changes
Comment thread lib/matplotlib/backends/backend_pdf.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

anntzer
anntzer reviewed Sep 16, 2025
View reviewed changes
Comment thread lib/matplotlib/backends/backend_pdf.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@QuLogic
QuLogic force-pushed the pdf-text-subsets branch from 60f3a4f to af3ea7f Compare September 17, 2025 01:38
@github-actions github-actions Bot removed the topic: text label Sep 17, 2025
@github-actions github-actions Bot removed backend: svg backend: cairo topic: text/mathtext labels Sep 17, 2025
@QuLogic QuLogic linked an issue Sep 17, 2025 that may be closed by this pull request
[Bug]: Math fonts (Type 3) incorrectly embedded in PDF? #21797
Closed
@QuLogic
QuLogic force-pushed the pdf-text-subsets branch from af3ea7f to e86ca1e Compare September 19, 2025 07:01
@QuLogic QuLogic removed the status: waiting for other PR label Sep 19, 2025
@QuLogic QuLogic moved this from Waiting for other PR to Ready for Review in Font and text overhaul Sep 19, 2025
@QuLogic
QuLogic force-pushed the pdf-text-subsets branch from e86ca1e to ad319c7 Compare September 19, 2025 07:34
@QuLogic
QuLogic marked this pull request as ready for review September 19, 2025 07:36
@github-actions github-actions Bot added the status: needs rebase label Sep 20, 2025
@QuLogic
QuLogic force-pushed the pdf-text-subsets branch from ad319c7 to cf9aff6 Compare September 22, 2025 21:20
@github-actions github-actions Bot removed the status: needs rebase label Sep 22, 2025
tacaswell
tacaswell approved these changes Sep 25, 2025
View reviewed changes
anntzer
anntzer approved these changes Sep 25, 2025
View reviewed changes
QuLogic added 4 commits September 25, 2025 19:05
@QuLogic
pdf: Improve text with characters outside embedded font limits
b70fb88
For character codes outside the embedded font limits (256 for type 3 and
65536 for type 42), we output them as XObjects instead of using text
commands. But there is nothing in the PDF spec that requires any
specific encoding like this.

Since we now support subsetting all fonts before embedding, split each
font into groups based on the maximum character code (e.g., 256-entry
groups for type 3), then switch text strings to a different font subset
and re-map character codes to it when necessary.

This means all text is true text (albeit with some strange encoding),
and we no longer need any XObjects for glyphs. For users of non-English
text, this means it will become selectable and copyable again.

Fixes matplotlib#21797
@QuLogic
pdf: Correct Unicode mapping for out-of-range font chunks
1c4af68
For Type 3 fonts, add a `ToUnicode` mapping (which was added in PDF
1.2), and for Type 42 fonts, correct the Unicode encoding, which should
be UTF-16BE, not UCS2.
@QuLogic
TST: Add emoji to multi-font text
6cedcf7
These characters are outside the BMP and should test subset splitting
for type 42 output in PDF.
@QuLogic
DOC: Add a release note for PDF font embedding fixes
c908bbf
@QuLogic
QuLogic force-pushed the pdf-text-subsets branch from cf9aff6 to c908bbf Compare September 26, 2025 00:08
@QuLogic

QuLogic commented Sep 26, 2025

Copy link
Copy Markdown
Member Author

Rebased without images (moved to text-overhaul-figures branch) so that it can be merged.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@QuLogic
QuLogic merged commit a1ed4ef into matplotlib:text-overhaul Sep 26, 2025
2 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@github-project-automation github-project-automation Bot moved this from Ready for Review to Done in Font and text overhaul Sep 26, 2025
@QuLogic
QuLogic deleted the pdf-text-subsets branch September 26, 2025 01:49
@QuLogic QuLogic mentioned this pull request Oct 3, 2025
Remove forced fallback from FT2Font::load_char #30627
Merged
1 task done
wavebyrd pushed a commit to wavebyrd/matplotlib that referenced this pull request Mar 13, 2026
@QuLogic
Merge pull request matplotlib#30512 from QuLogic/pdf-text-subsets
2ad9be1
pdf: Improve text with characters outside embedded font limits
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Apr 10, 2026
@QuLogic
Update test images for font/text overhaul
12d2a4d
This includes images changes for the following pull requests / commits:

* [Fix center of rotation with
  rotation_mode='anchor'](matplotlib#29199)
  (c44db77)
* [Remove ttconv backwards-compatibility
  code](matplotlib#30145)
  (8caff88)
* [Remove kerning_factor from
  tests](matplotlib#29816)
  (7b4d725)
* [Set text hinting to
  defaults](matplotlib#29816)
  (8255ae2)
* [Update FreeType to
  2.13.3](matplotlib#29816)
  (89c054d)
* [Implement text shaping with
  libraqm](matplotlib#30000)
  (b0ded3a,
  9813523)
* [Add language parameter to Text
  objects](matplotlib#29794)
  (7ce8eae)
* [Fix auto-sized glyphs with BaKoMa
  fonts](matplotlib#29936)
  (3ba2c13)
* [pdf: Improve text with characters outside embedded font
  limits](matplotlib#30512)
  (b70fb88,
  6cedcf7)
* [Prepare `CharacterTracker` for advanced font
  features](matplotlib#30608)
  (8274e17,
  70dc388,
  df670cf,
  ed5e074)
* [Add font feature API to
  Text](matplotlib#29695)
  (972a688)
* [Fix spacing in r"$\max
  f$"](matplotlib#30715)
  (4a99a83)
* [Implement libraqm for vector
  outputs](matplotlib#30607)
  (bd17cd4)
* [Drop the FT2Font intermediate
  buffer](matplotlib#30059)
  (9d7d7b4)
* [Rasterize dvi files without
  dvipng](matplotlib#30039)
  (7627118)
* [Update bundled FreeType and HarfBuzz
  libraries](matplotlib#30938)
  (a161658,
  9619bcc)
* [Fix positioning of wide mathtext
  accents](matplotlib#31069)
  (c2fa7ba)
* [Refactor RendererAgg.draw_{mathtext,text,tex} to use same base
  algorithm](matplotlib#31085)
  (931bcf3)
* [Implement TeX's fraction and script
  alignment](matplotlib#31046)
  (94ff452,
  4bfa0f9,
  1cd8510)
* [Fix confusion between text height and ascent in metrics
  calculations](matplotlib#31107)
  (60f2310)
* [mathtext: Fetch quad width & axis height from font
  metrics](matplotlib#31110)
  (692df3f,
  383028b)
* [mathtext: add mathnormal and distinguish between normal and italic
  family](matplotlib#31121)
  (a6913f3)
* [ENH: Ignore empty text for
  tightbbox](matplotlib#31285)
  (d772043)
* [Drop axis_artist tickdir image compat, due to text-overhaul
  merge](matplotlib#31281)
  (2057583)
* [text: Use font metrics to determine line
  heights](matplotlib#31291)
  (3ab6a27,
  d961462,
  97f4943)
* [ps/pdf: Override font height metrics to support AFM
  files](matplotlib#31371)
  (e0913d4)
* [TST: Cleanup back-compat code in tests touched by text
  overhaul](matplotlib#31295)
  (7c33379)
* [TST: Set tests touched by text overhaul to mpl20
  style](matplotlib#31300)
  (41c4d8d)
@QuLogic QuLogic mentioned this pull request Apr 10, 2026
Font and text overhaul #30161
Merged
4 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@tacaswell tacaswell tacaswell approved these changes
@anntzer anntzer anntzer approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

backend: pdf backend: ps

Projects

Font and text overhaul
Status: Done

Milestone

v3.11.0

Development

Successfully merging this pull request may close these issues.

[Bug]: Math fonts (Type 3) incorrectly embedded in PDF?

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@QuLogic @anntzer @tacaswell
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.