Add support for (some) colour fonts#30725
Add support for (some) colour fonts#30725QuLogic wants to merge 3 commits intomatplotlib:text-overhaulfrom
Conversation
| self._renderer.draw_image( | ||
| gc, | ||
| bitmap.left, bitmap.top - buffer.shape[0], | ||
| buffer[::-1, :, [2, 1, 0, 3]]) |
There was a problem hiding this comment.
I don't know if we really support big-endian archs, but at least backend_tkcairo uses (2, 1, 0, 3) if sys.byteorder == "little" else (1, 2, 3, 0).
There was a problem hiding this comment.
Endianness shouldn't matter as we aren't treating these as 32-bit integers, but I'll confirm when we build on Fedora for the release candidate.
src/ft2font_wrapper.cpp
Outdated
| return {{self.bitmap.rows, self.bitmap.width}, | ||
| if (self.bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) { | ||
| return { | ||
| py::array::ShapeContainer({self.bitmap.rows, self.bitmap.width, 4}), |
There was a problem hiding this comment.
Not that it really matters but I think the explicit ShapeContainer and StridesContainer are optional?
There was a problem hiding this comment.
It was because of mixed-signedness with the 4; changing it to 4u now makes them unnecessary.
|
So there is a small issue with transparent edges; you can see that they slightly darker than they should be. This is because FreeType produces colours with premultiplied alpha. By default, we use the "plain" pixel format, which does non-premultiplied colours into a non-premultiplied buffer. Agg does have multiple blender options, but those are: 1) plain colours to plain buffer, 2) premultiplied colours to premultiplied buffer, and 3) plain colours to premultiplied buffer. Unfortunately, that means it doesn't have the blender we need, premultiplied colours to non-premultiplied buffer. The simplest fix is to drop the buffer into Pillow and have it un-premultiply and then draw with our normal blender, but this may be a bit inefficient. |
|
Impressive! |
Probably not? We usually do plain->plain blending. I guess there's a division here, but not for demultiplying alpha: matplotlib/src/agg_workaround.h Lines 29 to 42 in 607d2c3 I've now added a test using a subset of OpenMoji Color in COLRv0 format. I forgot that Niklaas was just a sampler for a proprietary font, so that was a no-go. |
|
Rebased on top of #31085 as I think it makes this simpler to review. It also should mean that this is now independent of the font work going in for test image changes (other than requiring the new FreeType, of course). |
| if buffer.ndim == 3: | ||
| self._renderer.draw_text_bgra_image( | ||
| gc, | ||
| bitmap.left, bitmap.top - buffer.shape[0], |
There was a problem hiding this comment.
Why is the y different here from the monochrome case?
There was a problem hiding this comment.
I believe because we do the flip in Agg directly https://github.com/matplotlib/matplotlib/pull/30725/changes#diff-34559c7ee959645e82cd258d9684eab40456cbfa5b417fed59780e07ea670df7R835
There was a problem hiding this comment.
It doesn't have to be done as part of this PR, but I guess the semantics of draw_text_image could be made consistent with draw_text_rgba_image by adjusting things around
Line 760 in 67ebfc9
?
This adds support for fonts with colour glyphs supported by FreeType. Specifically, this should mean COLRv0 fonts. There also exist some other colour font types, which are not supported: * CBDT is a non-scalable bitmap format and we don't support those, but it may be possible if we do a scaling ourselves. matplotlib#31207 * COLRv1 essentially requires a full renderer setup. matplotlib#31210 * SBIX is another non-scalable bitmap format likee CBDT. matplotlib#31208 * SVG requires a parser (though it's some font-specific subset of the whole SVG spec). matplotlib#31211 Fixes matplotlib#31209


PR summary
This adds support for fonts with colour glyphs supported by FreeType. Specifically, this should mean COLRv0 fonts. There also exist some other colour font types, which are not supported:
We of course do have a full renderer available, but that would require much more interfacing to get working. HarfBuzz (which we use indirectly through libraqm) also has some API for these COLRv1 fonts, but I don't know if it's any nicer to use than FreeType's. Unfortunately, this does exclude one of the most popular emoji fonts, Noto Color Emoji, as that has moved to COLRv1+SVG.
This PR is based on all open font work, because a) #30059 makes it much easier to place the colour data if we don't have to use an intermediate buffer, and b) #30607 due to
FT_Glyph_To_Bitmaplosing colour information and so we need to move to an implementation that usesFT_Render_Glyphdirectly. I also merged #30334 though it's probably not strictly required.For example, we can now render Niklaas in COLRv0, some fonts with simpler decorative effects like Cairo Play, and the older OpenMoji Color that was COLRv0. Fonts that use SVG (like Nabla and Gilbert here) are reduced to their greyscale variant.

PR checklist