Skip to content

Commit f037be2

Browse files
committed
Handle some simpler colour fonts
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. * SVG requires a parser (though it's some font-specific subset of the whole SVG spec). * COLRv1 essentially requires a full renderer setup.
1 parent d0df260 commit f037be2

31 files changed

+143
-36
lines changed

lib/matplotlib/backends/backend_agg.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
189189
round(0x40 * (self.height - y + dx * sin + dy * cos))]
190190
)
191191
bitmap = font._render_glyph(
192-
glyph_index, get_hinting_flag(),
192+
glyph_index, get_hinting_flag() | LoadFlags.COLOR,
193193
RenderMode.NORMAL if gc.get_antialiased() else RenderMode.MONO)
194194
buffer = np.asarray(bitmap.buffer)
195195
if not gc.get_antialiased():
@@ -228,20 +228,38 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
228228
if ismath:
229229
return self.draw_mathtext(gc, x, y, s, prop, angle)
230230
font = self._prepare_font(prop)
231-
font.set_text(s, angle, flags=get_hinting_flag(),
232-
features=mtext.get_fontfeatures() if mtext is not None else None,
233-
language=mtext.get_language() if mtext is not None else None)
234-
for bitmap in font._render_glyphs(
235-
x, self.height - y,
236-
RenderMode.NORMAL if gc.get_antialiased() else RenderMode.MONO,
237-
):
231+
cos = math.cos(math.radians(angle))
232+
sin = math.sin(math.radians(angle))
233+
load_flags = get_hinting_flag() | LoadFlags.COLOR | LoadFlags.NO_SVG
234+
items = font._layout(
235+
s, flags=load_flags,
236+
features=mtext.get_fontfeatures() if mtext is not None else None,
237+
language=mtext.get_language() if mtext is not None else None)
238+
for item in items:
239+
hf = item.ft_object._hinting_factor
240+
item.ft_object._set_transform(
241+
[[round(0x10000 * cos / hf), round(0x10000 * -sin)],
242+
[round(0x10000 * sin / hf), round(0x10000 * cos)]],
243+
[round(0x40 * (x + item.x * cos - item.y * sin)),
244+
# FreeType's y is upwards.
245+
round(0x40 * (self.height - y + item.x * sin + item.y * cos))]
246+
)
247+
bitmap = item.ft_object._render_glyph(
248+
item.glyph_index, load_flags,
249+
RenderMode.NORMAL if gc.get_antialiased() else RenderMode.MONO)
238250
buffer = bitmap.buffer
239-
if not gc.get_antialiased():
240-
buffer *= 0xff
241-
self._renderer.draw_text_image(
242-
buffer,
243-
bitmap.left, int(self.height) - bitmap.top + buffer.shape[0],
244-
0, gc)
251+
if buffer.ndim == 3:
252+
self._renderer.draw_text_bgra_image(
253+
gc,
254+
bitmap.left, bitmap.top - buffer.shape[0],
255+
buffer)
256+
else:
257+
if not gc.get_antialiased():
258+
buffer *= 0xff
259+
self._renderer.draw_text_image(
260+
buffer,
261+
bitmap.left, int(self.height) - bitmap.top + buffer.shape[0],
262+
0, gc)
245263

246264
def get_text_width_height_descent(self, s, prop, ismath):
247265
# docstring inherited
-2.49 KB
Loading
15.3 KB
Loading
44.1 KB
Loading
44.1 KB
Loading
-1.38 KB
Loading
8.92 KB
Loading
41.2 KB
Loading
-1.81 KB
Loading
-2.68 KB
Loading

0 commit comments

Comments
 (0)