add color support to new text measuring functions

This commit is contained in:
nulano 2020-10-12 16:05:19 +01:00
parent 90e8255ba4
commit d7a08cbd15
4 changed files with 43 additions and 13 deletions

View File

@ -513,7 +513,7 @@ Methods
.. versionadded:: 6.2.0 .. versionadded:: 6.2.0
.. py:method:: ImageDraw.textlength(text, font=None, direction=None, features=None, language=None) .. py:method:: ImageDraw.textlength(text, font=None, direction=None, features=None, language=None, embedded_color=False)
Returns length (in pixels with 1/64 precision) of given text when rendered Returns length (in pixels with 1/64 precision) of given text when rendered
in font with provided direction, features, and language. in font with provided direction, features, and language.
@ -577,8 +577,9 @@ Methods
correct substitutions as appropriate, if available. correct substitutions as appropriate, if available.
It should be a `BCP 47 language code`_. It should be a `BCP 47 language code`_.
Requires libraqm. Requires libraqm.
:param embedded_color: Whether to use font embedded color glyphs (COLR or CBDT).
.. py:method:: ImageDraw.textbbox(xy, text, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0) .. py:method:: ImageDraw.textbbox(xy, text, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, embedded_color=False)
Returns bounding box (in pixels) of given text relative to given anchor Returns bounding box (in pixels) of given text relative to given anchor
when rendered in font with provided direction, features, and language. when rendered in font with provided direction, features, and language.
@ -625,8 +626,9 @@ Methods
It should be a `BCP 47 language code`_. It should be a `BCP 47 language code`_.
Requires libraqm. Requires libraqm.
:param stroke_width: The width of the text stroke. :param stroke_width: The width of the text stroke.
:param embedded_color: Whether to use font embedded color glyphs (COLR or CBDT).
.. py:method:: ImageDraw.multiline_textbbox(xy, text, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0) .. py:method:: ImageDraw.multiline_textbbox(xy, text, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, embedded_color=False)
Returns bounding box (in pixels) of given text relative to given anchor Returns bounding box (in pixels) of given text relative to given anchor
when rendered in font with provided direction, features, and language. when rendered in font with provided direction, features, and language.
@ -667,6 +669,7 @@ Methods
It should be a `BCP 47 language code`_. It should be a `BCP 47 language code`_.
Requires libraqm. Requires libraqm.
:param stroke_width: The width of the text stroke. :param stroke_width: The width of the text stroke.
:param embedded_color: Whether to use font embedded color glyphs (COLR or CBDT).
.. py:method:: getdraw(im=None, hints=None) .. py:method:: getdraw(im=None, hints=None)

View File

@ -500,15 +500,26 @@ class ImageDraw:
max_width = max(max_width, line_width) max_width = max(max_width, line_width)
return max_width, len(lines) * line_spacing - spacing return max_width, len(lines) * line_spacing - spacing
def textlength(self, text, font=None, direction=None, features=None, language=None): def textlength(
self,
text,
font=None,
direction=None,
features=None,
language=None,
embedded_color=False,
):
"""Get the length of a given string, in pixels with 1/64 precision.""" """Get the length of a given string, in pixels with 1/64 precision."""
if self._multiline_check(text): if self._multiline_check(text):
raise ValueError("can't measure length of multiline text") raise ValueError("can't measure length of multiline text")
if embedded_color and self.mode not in ("RGB", "RGBA"):
raise ValueError("Embedded color supported only in RGB and RGBA modes")
if font is None: if font is None:
font = self.getfont() font = self.getfont()
mode = "RGBA" if embedded_color else self.fontmode
try: try:
return font.getlength(text, self.fontmode, direction, features, language) return font.getlength(text, mode, direction, features, language)
except AttributeError: except AttributeError:
size = self.textsize( size = self.textsize(
text, font, direction=direction, features=features, language=language text, font, direction=direction, features=features, language=language
@ -529,8 +540,12 @@ class ImageDraw:
features=None, features=None,
language=None, language=None,
stroke_width=0, stroke_width=0,
embedded_color=False,
): ):
"""Get the bounding box of a given string, in pixels.""" """Get the bounding box of a given string, in pixels."""
if embedded_color and self.mode not in ("RGB", "RGBA"):
raise ValueError("Embedded color supported only in RGB and RGBA modes")
if self._multiline_check(text): if self._multiline_check(text):
return self.multiline_textbbox( return self.multiline_textbbox(
xy, xy,
@ -543,12 +558,14 @@ class ImageDraw:
features, features,
language, language,
stroke_width, stroke_width,
embedded_color,
) )
if font is None: if font is None:
font = self.getfont() font = self.getfont()
mode = "RGBA" if embedded_color else self.fontmode
bbox = font.getbbox( bbox = font.getbbox(
text, self.fontmode, direction, features, language, stroke_width, anchor text, mode, direction, features, language, stroke_width, anchor
) )
return bbox[0] + xy[0], bbox[1] + xy[1], bbox[2] + xy[0], bbox[3] + xy[1] return bbox[0] + xy[0], bbox[1] + xy[1], bbox[2] + xy[0], bbox[3] + xy[1]
@ -564,6 +581,7 @@ class ImageDraw:
features=None, features=None,
language=None, language=None,
stroke_width=0, stroke_width=0,
embedded_color=False,
): ):
if direction == "ttb": if direction == "ttb":
raise ValueError("ttb direction is unsupported for multiline text") raise ValueError("ttb direction is unsupported for multiline text")
@ -583,7 +601,12 @@ class ImageDraw:
) )
for line in lines: for line in lines:
line_width = self.textlength( line_width = self.textlength(
line, font, direction=direction, features=features, language=language line,
font,
direction=direction,
features=features,
language=language,
embedded_color=embedded_color,
) )
widths.append(line_width) widths.append(line_width)
max_width = max(max_width, line_width) max_width = max(max_width, line_width)
@ -625,6 +648,7 @@ class ImageDraw:
features=features, features=features,
language=language, language=language,
stroke_width=stroke_width, stroke_width=stroke_width,
embedded_color=embedded_color,
) )
if bbox is None: if bbox is None:
bbox = bbox_line bbox = bbox_line

View File

@ -290,9 +290,7 @@ class FreeTypeFont:
:return: Width for horizontal, height for vertical text. :return: Width for horizontal, height for vertical text.
""" """
return ( return self.font.getlength(text, mode, direction, features, language) / 64
self.font.getlength(text, mode == "1", direction, features, language) / 64
)
def getbbox( def getbbox(
self, self,
@ -352,7 +350,7 @@ class FreeTypeFont:
:return: ``(left, top, right, bottom)`` bounding box :return: ``(left, top, right, bottom)`` bounding box
""" """
size, offset = self.font.getsize( size, offset = self.font.getsize(
text, mode == "1", direction, features, language, anchor text, mode, direction, features, language, anchor
) )
left, top = offset[0] - stroke_width, offset[1] - stroke_width left, top = offset[0] - stroke_width, offset[1] - stroke_width
width, height = size[0] + 2 * stroke_width, size[1] + 2 * stroke_width width, height = size[0] + 2 * stroke_width, size[1] + 2 * stroke_width

View File

@ -624,6 +624,8 @@ font_getlength(FontObject* self, PyObject* args)
size_t i, count; /* glyph_info index and length */ size_t i, count; /* glyph_info index and length */
int horizontal_dir; /* is primary axis horizontal? */ int horizontal_dir; /* is primary axis horizontal? */
int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */ int mask = 0; /* is FT_LOAD_TARGET_MONO enabled? */
int color = 0; /* is FT_LOAD_COLOR enabled? */
const char *mode = NULL;
const char *dir = NULL; const char *dir = NULL;
const char *lang = NULL; const char *lang = NULL;
PyObject *features = Py_None; PyObject *features = Py_None;
@ -631,13 +633,16 @@ font_getlength(FontObject* self, PyObject* args)
/* calculate size and bearing for a given string */ /* calculate size and bearing for a given string */
if (!PyArg_ParseTuple(args, "O|izOz:getlength", &string, &mask, &dir, &features, &lang)) { if (!PyArg_ParseTuple(args, "O|zzOz:getlength", &string, &mode, &dir, &features, &lang)) {
return NULL; return NULL;
} }
horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1; horizontal_dir = dir && strcmp(dir, "ttb") == 0 ? 0 : 1;
count = text_layout(string, self, dir, features, lang, &glyph_info, mask); mask = mode && strcmp(mode, "1") == 0;
color = mode && strcmp(mode, "RGBA") == 0;
count = text_layout(string, self, dir, features, lang, &glyph_info, mask, color);
if (PyErr_Occurred()) { if (PyErr_Occurred()) {
return NULL; return NULL;
} }