Skip to content

Replace ttconv by plain python for pdf subsetting #18181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 13, 2020

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Aug 5, 2020

PR Summary

First commit:

Switch from a hand-written glyph outline decomposer to FreeType's one.

Instead of walking through FT_Outline ourselves, use FreeType's
FT_Outline_Decompose to decompose glyphs into paths.

Fixes incorrect positioning of first and last control points of certain
contours; compare e.g.

from pylab import *
from matplotlib.textpath import TextPath
from matplotlib.patches import PathPatch

rcParams["mathtext.fontset"] = "stixsans"
path = TextPath((0, 0), r"$\delta$", size=72)
plot(*path.vertices.T, ".-", lw=.5)
gca().add_patch(PathPatch(path, alpha=.5))
gca().set(aspect="equal")
show()

before and after the patch (before the patch, the inner loop was not
properly closed). (Technically, I believe the earlier bug affected
start/end-of-contours that are implicitly created per the ttf format at
the midpoint between two conic control points.)

before:
old

after:
new

A few SVG files need to be updated too.

Second commit:

Stop using ttconv for pdf.

Quite a bit of work goes into reproducing quirks of the old ttconv code
in order not to update baseline images, but this can easily be dropped
once the new baseline images system goes in.

figure_align_label.pdf gets modified because of tiny differences in
outline extraction (due to the ttconv emulation); there's already the
svg test that tests the fixed-dpi case so I feel OK deleting it.

This also fixes ttc subsetting for pdf output (cf. changes in
test_font_manager.py).


(PostScript is not done yet, but it's basically the same idea, it's just the header that's different.)

Fixes #17197. I'll skip adding a new font for the test, because in essence we're "just" relying on FreeType handing us the right outlines.

PR Checklist

  • Has Pytest style unit tests
  • Code is Flake 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/next_api_changes/* if API changed in a backward-incompatible way

@QuLogic
Copy link
Member

QuLogic commented Aug 7, 2020

Instead of walking through FT_Outline ourselves, use FreeType's
FT_Outline_Decompose to decompose glyphs into paths.

Cool, I wanted to do that, except for it breaking images, like you've found.

Copy link
Member

@QuLogic QuLogic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't completely finish the second commit yet, though it seems good.

src/_path.h Outdated
Comment on lines 1111 to 1113
while (q >= str && *q == '0') { --q; }
// If the end is a decimal point, delete that too
if (q >= str && *q == '.') { --q; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stylistically, this might be against PEP7.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, but I think splitting things on their own lines (as was done before) makes the code really harder to follow because the information density is so low...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went for a slight variation which does respect pep7.

@anntzer anntzer force-pushed the unttpdf branch 2 times, most recently from 586edd9 to dd0482b Compare August 7, 2020 09:37
Copy link
Member

@jkseppan jkseppan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Looks like much of the complexity is for bug-compatibility with ttconv, which I hope we can remove later.

Instead of walking through FT_Outline ourselves, use FreeType's
FT_Outline_Decompose to decompose glyphs into paths.

Fixes incorrect positioning of first and last control points of certain
contours; compare e.g.
```python
from pylab import *
from matplotlib.textpath import TextPath
from matplotlib.patches import PathPatch

rcParams["mathtext.fontset"] = "stixsans"
path = TextPath((0, 0), r"$\delta$", size=72)
plot(*path.vertices.T, ".-", lw=.5)
gca().add_patch(PathPatch(path, alpha=.5))
gca().set(aspect="equal")
show()
```
before and after the patch (before the patch, the inner loop was not
properly closed).  (Technically, I believe the earlier bug affected
start/end-of-contours that are implicitly created per the ttf format at
the midpoint between two conic control points.)

A few SVG files need to be updated too.
@anntzer anntzer force-pushed the unttpdf branch 2 times, most recently from d81d35b to 385894b Compare August 9, 2020 22:13
--c;
}
try {
buffer.append(str, c + 1);
Copy link
Member

@QuLogic QuLogic Aug 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second parameter is size, isn't it? Or is cppreference wrong, since it seems to compile...

Suggested change
buffer.append(str, c + 1);
buffer.append(str, c - str + 1);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is using the

template< class InputIt >
basic_string& append( InputIt first, InputIt last );

overload, not the

basic_string& append( const CharT* s, size_type count );

one.

@anntzer
Copy link
Contributor Author

anntzer commented Aug 12, 2020

One thing I forgot to mention is that the Py_DTSF_ADD_DOT_0 change also fixes a separate bug in __add_number, whereby passing precision = 0 would previously print values without the dot and then trailing but significant zeros would be incorrectly stripped out. This doesn't affect the patch here because this uses the separate bug-compat precision=-1 path, but the (future) backend_ps patch will use precision=0 and thus benefit from this.

Quite a bit of work goes into reproducing quirks of the old ttconv code
in order not to update baseline images, but this can easily be dropped
once the new baseline images system goes in.

figure_align_label.pdf gets modified because of tiny differences in
outline extraction (due to the ttconv emulation); there's already the
svg test that tests the fixed-dpi case so I feel OK deleting it.

This also fixes ttc subsetting for pdf output (cf. changes in
test_font_manager.py).
@QuLogic
Copy link
Member

QuLogic commented Aug 13, 2020

Should we wait for the baseline image PR before merging this?

@anntzer
Copy link
Contributor Author

anntzer commented Aug 13, 2020

I put in all the bug-compat code explicitly to minimize the image diffs; I'd say the remaining svg diffs are not too large, but I'm not in a big hurry either.

@jklymak jklymak added this to the v3.4.0 milestone Aug 13, 2020
@jklymak jklymak merged commit c9bf76c into matplotlib:master Aug 13, 2020
@jklymak
Copy link
Member

jklymak commented Aug 13, 2020

I'll merge since @anntzer is the main person concerned with images changing 😉

@anntzer anntzer mentioned this pull request May 1, 2025
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missing character upon savefig() with Free Serif font
4 participants