Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Update FreeType to 2.13.3 #29816

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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open

Update FreeType to 2.13.3 #29816

wants to merge 12 commits into from

Conversation

QuLogic
Copy link
Member

@QuLogic QuLogic commented Mar 27, 2025

PR summary

On the call last week, we considered whether it made sense to do this upgrade. This PR shows the effect of doing so. Note for simplicity, I simply copied the new images from https://github.com/QuLogic/mpl-images, and then updated any new images directly. It's possible that there were some extraneously changed images as a result. I will check this shortly.

The latest FreeType version supports many newer font features, and fixes several CVEs, which we were mostly hoping were not relevant to us, but this may or may not be true. Additionally, I've found that libraqm runs into issues with hinting in older versions. While I'm not entirely sure which of libraqm or FreeType holds that bug, updating libraqm to new versions would also require newer FreeType anyway.

The main concern here was the repo size. Locally, I started with a completely fresh clone before creating this commit. The .git directory increased from 461M to 482M, or an increase of 21M / 4.6%.

PR checklist

@QuLogic
Copy link
Member Author

QuLogic commented Mar 27, 2025

Another size test:

$ git clone https://github.com/matplotlib/matplotlib.git mpl
$ cd mpl
$ du -hsc .git
461M	.git
461M	total

$ git fetch https://github.com/QuLogic/matplotlib.git ft213:ft213
$ du -hsc .git
477M	.git
477M	total

So once everything is repacked and compressed by git, the repo only gains 16M!

@anntzer
Copy link
Contributor

anntzer commented Mar 27, 2025

If we're going to regen the baselines, we should also take that opportunity to remove some of the backcompat knobs -- at least text.kerning_factor (which clearly only existed to avoid regen'ing the baselines), and possibly text.hinting_factor as well (at least I would switch the default to 1 and generate the images with that amount of hinting, even if we decide to keep this functionality).

@tacaswell
Copy link
Member

Rather than regenerating the images at this point, I would start by pulling the tolerances used by Fedora upstream (so we can backport that to 3.10.x) and then in a second step regenerate the images on main and push the tolerances back to 0.

@QuLogic
Copy link
Member Author

QuLogic commented Mar 27, 2025

If we're going to regen the baselines, we should also take that opportunity to remove some of the backcompat knobs -- at least text.kerning_factor (which clearly only existed to avoid regen'ing the baselines), and possibly text.hinting_factor as well (at least I would switch the default to 1 and generate the images with that amount of hinting, even if we decide to keep this functionality).

Yes, good point; I will see what effect that has on things.

Rather than regenerating the images at this point, I would start by pulling the tolerances used by Fedora upstream (so we can backport that to 3.10.x) and then in a second step regenerate the images on main and push the tolerances back to 0.

Fedora doesn't have any other tolerances other than the 6 other files already changed (though in this PR I changed the results instead of the tolerance, we could do like in Fedora instead). For image tests, we overlay the correct images from my mpl-images repo and don't change any global tolerance.

@QuLogic
Copy link
Member Author

QuLogic commented Mar 28, 2025

Removing kerning_factor from _classic_test.patch causes an additional 100 test failures over this PR. Top 20 RMS are:

  • lib/matplotlib/tests/test_backend_pdf.py::test_kerning[pdf] 23.532
  • lib/matplotlib/tests/test_arrow_patches.py::test_boxarrow[png] 20.492
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout9[png] 17.849
  • lib/matplotlib/tests/test_mathtext.py::test_mathtext_rendering_lightweight[png-mathtext1-dejavusans-8] 17.244
  • lib/matplotlib/tests/test_table.py::test_auto_column[png] 16.872
  • lib/matplotlib/tests/test_text.py::test_basic_wrap[png] 15.712
  • lib/matplotlib/tests/test_axes.py::test_pie_nolabel_but_legend[png] 12.626
  • lib/matplotlib/tests/test_tightlayout.py::test_tight_layout7[pdf] 12.406
  • lib/matplotlib/tests/test_mathtext.py::test_mathtext_rendering[pdf-mathtext-dejavusans-46] 11.002
  • lib/matplotlib/tests/test_axes.py::test_stairs_datetime[png] 10.796
  • lib/matplotlib/tests/test_tightlayout.py::test_tight_layout7[png] 10.388
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout5[png] 10.191
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout2[png] 10.191
  • lib/matplotlib/tests/test_tightlayout.py::test_tight_layout7[svg] 9.704
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout4[png] 9.014
  • lib/matplotlib/tests/test_legend.py::test_multiple_keys[png] 8.322
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout3[png] 7.658
  • lib/matplotlib/tests/test_mathtext.py::test_mathtext_rendering[pdf-mathtext-dejavuserif-60] 7.572
  • lib/matplotlib/tests/test_text.py::test_font_styles[pdf] 7.355
  • lib/matplotlib/tests/test_constrainedlayout.py::test_constrained_layout15[png] 7.259

I'll commit these all separately to make it easier to review, but we can squash these all together if it's all working fine. The majority of these are things like Te, te, x, er all kern a little bit closer together now.

@QuLogic
Copy link
Member Author

QuLogic commented Mar 28, 2025

On a related note, and I'm not sure which ones are relevant here, but I wonder if we should drop several PDF and SVG test images when they would be changed but don't effectively test anything different from the PNG.

@jklymak
Copy link
Member

jklymak commented Mar 28, 2025

For the repo size problem we could provide some guidance for the depth flag so most contributors don't need to download the whole thing. Eg --depth=500 gets you the last two years of commits and is x MB. Most folks don't need the full commit history (or even anything more than depth=1)

@greglucas
Copy link
Contributor

The first image comparison that shows up lib/matplotlib/tests/baseline_images/test_agg/agg_filter.png doesn't have any text in it at all so is presumably not an update due to freetype. Is this all images that have had tolerances ever adjusted in the past? If so, do you know if there would be any size difference with just text-based freetype updates versus all others?

Is it beneficial/necessary to grab the images from that other repo you've been keeping, or would it make sense to blow away the images directory on CI and move all the resultant images into the directory to start fresh in a sense?

@QuLogic
Copy link
Member Author

QuLogic commented Mar 28, 2025

and possibly text.hinting_factor as well (at least I would switch the default to 1 and generate the images with that amount of hinting, even if we decide to keep this functionality).

Surprisingly, this doesn't appear to make any difference to test images. It only affects 9 tests, and only with regards to bboxes and tight layout that are explicitly compared. This doesn't matter whether I try with FreeType 2.6.1 or 2.13.3.

The first image comparison that shows up lib/matplotlib/tests/baseline_images/test_agg/agg_filter.png doesn't have any text in it at all so is presumably not an update due to freetype. Is this all images that have had tolerances ever adjusted in the past? If so, do you know if there would be any size difference with just text-based freetype updates versus all others?

Ah, you're right. I had not done a deep dive into the changes, but likely this was an image that had text that was removed, so it was regenerated from the FreeType changes, but effectively looked the same. I will go through these again and make sure we don't have any extraneous changes like this one.

Is it beneficial/necessary to grab the images from that other repo you've been keeping, or would it make sense to blow away the images directory on CI and move all the resultant images into the directory to start fresh in a sense?

The other repo was useful for tracking purposes and a quick changeover, but it might be best to start fresh and make sure we don't change too many extra images.

@QuLogic
Copy link
Member Author

QuLogic commented Mar 29, 2025

I haven't updated this PR for it yet, but going over the diffs, one surprising change is that while the mathtext tests with DejaVu Sans look better (more consistent baselines, tweaks to kerning), the same ones with Computer Modern look worse (mostly due to a wobbly baseline.) But on the other hand, a lot of those had the wobbly baseline before...

I've also opened #29827 to remove most of the redundant PDFs that would be changed here (except the ones from test_backend_pdf, plus a few others noted in that PR).

@anntzer
Copy link
Contributor

anntzer commented Mar 29, 2025

See also #14177 (comment) and #22459 re: wobbly baseline. I have some hopes that switching agg+usetex to rasterizing glyphs ourselves (see also #29807) would be one way to fix that.

@oscargus
Copy link
Member

Slightly unrelated, but if we decide to update this many PNGs, it should be a good time to add an oxipng pre-commit hook. https://github.com/shssoichiro/oxipng I would expect that the sizes are halved or so on average. (It would be useful independent of this, but I have not gotten around to propose it and it would be unfortunate to change all those images without compression.)

@QuLogic
Copy link
Member Author

QuLogic commented Apr 1, 2025

See also #14177 (comment) and #22459 re: wobbly baseline. I have some hopes that switching agg+usetex to rasterizing glyphs ourselves (see also #29807) would be one way to fix that.

But these are not usetex, just plain mathtext. However, thanks to those links, I've come across #5414 which claimed to fix the wobbly baseline. It turns out that that isn't due to changing to external FreeType, but to a change in MathtextBackendAgg.render_glyph. Copying that out fixes all the wobbly baselines, both before and after updating FreeType.

Unfortunately, updating FreeType still causes changes in those test images due to different kerning and metrics (the whole line may move up/down a pixel, but individual glyphs no longer do.) So I'm going to roll that change in here for the changed images to be squashed together.

@QuLogic
Copy link
Member Author

QuLogic commented Apr 1, 2025

I've now rebased this on top of #29827, and gone through and removed the extra image changes. Now it's about 60% the number it was before.

As I expect this will be squashed, there are a few things here:

  1. Fixing the wobbly baseline in mathtext (e.g., for the Latin alphabet, the t is no longer floating, while for the Greek alphabet, everything shifts down to match theta).
  2. Updating to FreeType 2.13.3.
  3. Removing the kerning_factor setting from the tests (the majority of these are things like Te, te, x, er all kerning a little bit closer.)
  4. Removing any compatibility styling flags on images that were already regenerated.
  5. Compressing everything that was already changed with oxipng; this compresses from about 12M to 7M.

@anntzer
Copy link
Contributor

anntzer commented Apr 1, 2025

Are the new tests also using hinting_factor=1?

@QuLogic
Copy link
Member Author

QuLogic commented Apr 1, 2025

No, as I mentioned earlier, that barely changed anything. I'm trying to see if that's true or whether I didn't set it up right.

@ksunden ksunden mentioned this pull request May 2, 2025
2 tasks
@ksunden ksunden modified the milestones: v3.10.2, v3.10.3 May 2, 2025
@QuLogic
Copy link
Member Author

QuLogic commented May 3, 2025

I pushed to https://github.com/anntzer/matplotlib/tree/mt1 an updated version of #15539 #15339, which I think should be worth looking at to merge with the baseline changes here (it changes all the baseline images). Note that the version I pushed doesn't contain, for now, the updated baseline images (you need run the tests and accept all changes).

I ran this, and without checking the changes, it will change several of the images changed here, with the addition of:

  • lib/matplotlib/tests/test_ft2font.py::test_ft2font_drawing
  • lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf
  • lib/matplotlib/tests/baseline_images/test_backend_ps/type42_without_prep.eps
  • lib/matplotlib/tests/baseline_images/test_contour/contour_log_locator.svg
  • lib/matplotlib/tests/baseline_images/test_text/text_alignment.svg
  • lib/matplotlib/tests/baseline_images/test_text/text_pdf_chars_beyond_bmp.pdf
  • lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg
  • almost all of the PDF and many of the SVG that are in lib/matplotlib/tests/baseline_images/test_mathtext/ (note that all the PNG there were already changed)

The change would be the patch below, which indeed again changes a bunch of baseline images; I haven't checked how much are files already touched by this PR.

There are not really a whole bunch of changes here; only 111 tests. Again, I didn't do a full review yet, but it will change:

  • lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.pdf
  • lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.pdf
  • lib/matplotlib/tests/baseline_images/test_backend_pdf/multi_font_type3.pdf
  • lib/matplotlib/tests/baseline_images/test_backend_pdf/truetype-conversion.pdf
  • lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.pdf
  • lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf
  • lib/matplotlib/tests/baseline_images/test_contour/contour_rasterization.pdf
  • lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.pdf
  • lib/matplotlib/tests/baseline_images/test_legend/framealpha.pdf
  • lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf
  • lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.pdf
  • lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg
  • lib/matplotlib/tests/baseline_images/test_text/multiline.pdf
  • lib/matplotlib/tests/baseline_images/test_text/multiline2.pdf
  • lib/matplotlib/tests/baseline_images/test_text/text_alignment.pdf
  • lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.pdf
  • lib/matplotlib/tests/baseline_images/test_text/titles.pdf
  • many, but not nearly all, PDF and SVG in lib/matplotlib/tests/baseline_images/test_mathtext/ again

I have pushed the corresponding test image changes here for now: https://github.com/QuLogic/matplotlib/tree/ft213-additions

Comment on lines 179 to 184
image = np.asarray(image)
while h and (image[0] == 0).all():
image = image[1:]
while d and (image[-1] == 0).all():
image = image[:-1]
return RasterParse(xmin, 0, w, h + d, d, image)
Copy link
Member Author

Choose a reason for hiding this comment

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

@anntzer h and d don't change in these loops; are they supposed to be reduced each time?

Copy link
Member Author

Choose a reason for hiding this comment

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

And doesn't this trim too much? If you render a degree sign, this will trim everything above/below the circle, but the y offset is still 0?

plt.text(0.5, 0, '$\\degree$')
plt.xlim(0, 1)
plt.ylim(0, 1)

On main:
Figure_1
vs this branch:
Figure_1

Copy link
Contributor

@anntzer anntzer May 7, 2025

Choose a reason for hiding this comment

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

Yes, sorry about that, I had noticed this earlier and force-pushed a version of the mt1 branch where I am also more careful with positioning the origin of the rasterized image relative to the origin of the text string, can you try again? I think that fixes the problem.

mdboom and others added 12 commits May 7, 2025 06:27
Namely, `text.hinting` is now `default` instead of `force_autohint` (or
`none` for classic tests) and `text.hinting_factor` is now 1, not 8.
If we've updated an image in the past couple commits, then we can remove
the backwards-compatibility styling so that they're generated as
intended.
The `FontInfo.num` value returned by `TruetypeFonts._get_info` is a
character code, but `FT2Font.get_kerning` takes *glyph indices*, meaning
that kerning was likely off in most cases.
@oscargus
Copy link
Member

Maybe this is a good time to revive #23189? (If we still are going to change the rendering of text.)

There are two things there:

  1. More accents (which could be a stand-alone thing anyway)
  2. Use the correct character with accent if such exists, rather than drawing an accent in the same location as the character.

I can try to joint the next call.

@anntzer
Copy link
Contributor

anntzer commented May 12, 2025

#30043 (fix alpha compositing by ft2font) could also be considered for being squashed with this.
Edit: or perhaps even more generally #30059 -- direct rendering into the Agg buffer, rather than trying to do the compositing ourselves.

@tacaswell tacaswell mentioned this pull request May 15, 2025
7 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.

Determine if hinting_factor setting can be dropped
9 participants