From 406fe59242ad288bcd9f9fe663b227620eacd344 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 May 2022 01:57:13 +0100 Subject: [PATCH 01/19] deprecate font.getsize and related functions --- src/PIL/ImageDraw.py | 66 +++++++++++++++++++++++++++++++++++--------- src/PIL/ImageFont.py | 27 +++++++++++++++--- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 3824626bd6a..4e5ee24b71c 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -34,6 +34,7 @@ import numbers from . import Image, ImageColor +from ._deprecate import deprecate """ A simple 2D drawing interface for PIL images. @@ -372,6 +373,18 @@ def _multiline_split(self, text): return text.split(split_character) + def _multiline_spacing(self, font, spacing, stroke_width): + # this can be replaced with self.textbbox(...)[3] when textsize is removed + return ( + self.textsize( + "A", + font=font, + stroke_width=stroke_width, + __internal__=True, + )[1] + + spacing + ) + def text( self, xy, @@ -511,9 +524,7 @@ def multiline_text( widths = [] max_width = 0 lines = self._multiline_split(text) - line_spacing = ( - self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing - ) + line_spacing = self._multiline_spacing(font, spacing, stroke_width) for line in lines: line_width = self.textlength( line, font, direction=direction, features=features, language=language @@ -571,16 +582,33 @@ def textsize( features=None, language=None, stroke_width=0, + __internal__=False, ): """Get the size of a given string, in pixels.""" + if not __internal__: + deprecate("textsize", 10, "textbbox or textlength") if self._multiline_check(text): return self.multiline_textsize( - text, font, spacing, direction, features, language, stroke_width + text, + font, + spacing, + direction, + features, + language, + stroke_width, + __internal__=True, ) if font is None: font = self.getfont() - return font.getsize(text, direction, features, language, stroke_width) + return font.getsize( + text, + direction, + features, + language, + stroke_width, + __internal__=True, + ) def multiline_textsize( self, @@ -591,15 +619,23 @@ def multiline_textsize( features=None, language=None, stroke_width=0, + __internal__=False, ): + if not __internal__: + deprecate("multiline_textsize", 10, "multiline_textbbox") max_width = 0 lines = self._multiline_split(text) - line_spacing = ( - self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing - ) + line_spacing = self._multiline_spacing(font, spacing, stroke_width) for line in lines: line_width, line_height = self.textsize( - line, font, spacing, direction, features, language, stroke_width + line, + font, + spacing, + direction, + features, + language, + stroke_width, + __internal__=True, ) max_width = max(max_width, line_width) return max_width, len(lines) * line_spacing - spacing @@ -625,8 +661,14 @@ def textlength( try: return font.getlength(text, mode, direction, features, language) except AttributeError: + deprecate("textlength support for fonts without getlength", 10) size = self.textsize( - text, font, direction=direction, features=features, language=language + text, + font, + direction=direction, + features=features, + language=language, + __internal__=True, ) if direction == "ttb": return size[1] @@ -704,9 +746,7 @@ def multiline_textbbox( widths = [] max_width = 0 lines = self._multiline_split(text) - line_spacing = ( - self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing - ) + line_spacing = self._multiline_spacing(font, spacing, stroke_width) for line in lines: line_width = self.textlength( line, diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 681b75d448b..38fc24d7481 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -143,6 +143,8 @@ def getsize(self, text, *args, **kwargs): :return: (width, height) """ + if not kwargs.get("__internal__"): + deprecate("getsize", 10, "getbbox or getlength") return self.font.getsize(text) def getmask(self, text, mode="", *args, **kwargs): @@ -386,7 +388,13 @@ def getbbox( return left, top, left + width, top + height def getsize( - self, text, direction=None, features=None, language=None, stroke_width=0 + self, + text, + direction=None, + features=None, + language=None, + stroke_width=0, + __internal__=False, ): """ Returns width and height (in pixels) of given text if rendered in font with @@ -438,6 +446,8 @@ def getsize( :return: (width, height) """ + if not __internal__: + deprecate("getsize", 10, "getbbox or getlength") # vertical offset is added for historical reasons # see https://github.com/python-pillow/Pillow/pull/4910#discussion_r486682929 size, offset = self.font.getsize(text, "L", direction, features, language) @@ -495,12 +505,15 @@ def getsize_multiline( :return: (width, height) """ + deprecate("getsize_multiline", 10) max_width = 0 lines = self._multiline_split(text) - line_spacing = self.getsize("A", stroke_width=stroke_width)[1] + spacing + line_spacing = ( + self.getsize("A", stroke_width=stroke_width, __internal__=True)[1] + spacing + ) for line in lines: line_width, line_height = self.getsize( - line, direction, features, language, stroke_width + line, direction, features, language, stroke_width, __internal__=True ) max_width = max(max_width, line_width) @@ -516,6 +529,7 @@ def getoffset(self, text): :return: A tuple of the x and y offset """ + deprecate("getoffset", 10, "getbbox") return self.font.getsize(text)[1] def getmask( @@ -796,7 +810,12 @@ def __init__(self, font, orientation=None): self.orientation = orientation # any 'transpose' argument, or None def getsize(self, text, *args, **kwargs): - w, h = self.font.getsize(text) + if not kwargs.get("__internal__"): + deprecate("getsize", 10, "getbbox or getlength") + try: + w, h = self.font.getsize(text, __internal__=True) + except TypeError: + w, h = self.font.getsize(text) if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): return h, w return w, h From c854bf8d1c05022bec4309fbf6b547e494db9373 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 May 2022 18:06:20 +0100 Subject: [PATCH 02/19] add getbbox and getlength to basic ImageFont and update related tests --- Tests/test_imagedraw.py | 28 +++++++++++++++++++++++----- Tests/test_imagefont.py | 7 +++++-- src/PIL/ImageDraw.py | 4 ---- src/PIL/ImageFont.py | 27 +++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 69d1ac9fad3..dca7bfe6a58 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -1232,9 +1232,10 @@ def test_textsize_empty_string(): # Act # Should not cause 'SystemError: returned NULL without setting an error' - draw.textsize("") - draw.textsize("\n") - draw.textsize("test\n") + draw.textbbox((0, 0), "") + draw.textbbox((0, 0), "\n") + draw.textbbox((0, 0), "test\n") + draw.textlength("") @skip_unless_feature("freetype2") @@ -1245,8 +1246,25 @@ def test_textsize_stroke(): font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20) # Act / Assert - assert draw.textsize("A", font, stroke_width=2) == (16, 20) - assert draw.multiline_textsize("ABC\nAaaa", font, stroke_width=2) == (52, 44) + assert draw.textbbox((2, 2), "A", font, stroke_width=2) == (0, 4, 16, 20) + assert draw.textbbox((2, 2), "A", font, stroke_width=4) == (-2, 2, 18, 22) + assert draw.textbbox((2, 2), "ABC\nAaaa", font, stroke_width=2) == (0, 4, 52, 44) + assert draw.textbbox((2, 2), "ABC\nAaaa", font, stroke_width=4) == (-2, 2, 54, 50) + + +def test_textsize_deprecation(): + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im) + + with pytest.warns(DeprecationWarning) as log: + draw.textsize("Hello") + assert len(log) == 1 + with pytest.warns(DeprecationWarning) as log: + draw.textsize("Hello\nWorld") + assert len(log) == 1 + with pytest.warns(DeprecationWarning) as log: + draw.multiline_textsize("Hello\nWorld") + assert len(log) == 1 @skip_unless_feature("freetype2") diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 0c50303f902..fe7d79f82e2 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -720,8 +720,11 @@ def test_textbbox_non_freetypefont(self): im = Image.new("RGB", (200, 200)) d = ImageDraw.Draw(im) default_font = ImageFont.load_default() - with pytest.raises(ValueError): - d.textbbox((0, 0), "test", font=default_font) + with pytest.warns(DeprecationWarning) as log: + width, height = d.textsize("test", font=default_font) + assert len(log) == 1 + assert d.textlength("test", font=default_font) == width + assert d.textbbox((0, 0), "test", font=default_font) == (0, 0, width, height) @pytest.mark.parametrize( "anchor, left, top", diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 4e5ee24b71c..723ec17fdc1 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -709,10 +709,6 @@ def textbbox( if font is None: font = self.getfont() - from . import ImageFont - - if not isinstance(font, ImageFont.FreeTypeFont): - raise ValueError("Only supported for TrueType fonts") mode = "RGBA" if embedded_color else self.fontmode bbox = font.getbbox( text, mode, direction, features, language, stroke_width, anchor diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 38fc24d7481..4e2cb9686df 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -167,6 +167,33 @@ def getmask(self, text, mode="", *args, **kwargs): """ return self.font.getmask(text, mode) + def getbbox(self, text, *args, **kwargs): + """ + Returns bounding box (in pixels) of given text. + + .. versionadded:: 9.2.0 + + :param text: Text to render. + :param mode: Used by some graphics drivers to indicate what mode the + driver prefers; if empty, the renderer may return either + mode. Note that the mode is always a string, to simplify + C-level implementations. + + :return: ``(left, top, right, bottom)`` bounding box + """ + width, height = self.font.getsize(text) + return 0, 0, width, height + + def getlength(self, text, *args, **kwargs): + """ + Returns length (in pixels) of given text. + This is the amount by which following text should be offset. + + .. versionadded:: 9.2.0 + """ + width, height = self.font.getsize(text) + return width + ## # Wrapper for FreeType fonts. Application code should use the From f34a6460ef0925679b6c810fa363bcabcf56458b Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 May 2022 18:23:37 +0100 Subject: [PATCH 03/19] update test_font_pcf to use getbbox --- Tests/test_font_pcf.py | 8 ++++++-- Tests/test_font_pcf_charsets.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Tests/test_font_pcf.py b/Tests/test_font_pcf.py index 288848f2619..885ef843372 100644 --- a/Tests/test_font_pcf.py +++ b/Tests/test_font_pcf.py @@ -68,12 +68,16 @@ def test_textsize(request, tmp_path): tempname = save_font(request, tmp_path) font = ImageFont.load(tempname) for i in range(255): - (dx, dy) = font.getsize(chr(i)) + (ox, oy, dx, dy) = font.getbbox(chr(i)) + assert ox == 0 + assert oy == 0 assert dy == 20 assert dx in (0, 10) + assert font.getlength(chr(i)) == dx for i in range(len(message)): msg = message[: i + 1] - assert font.getsize(msg) == (len(msg) * 10, 20) + assert font.getlength(msg) == len(msg) * 10 + assert font.getbbox(msg) == (0, 0, len(msg) * 10, 20) def _test_high_characters(request, tmp_path, message): diff --git a/Tests/test_font_pcf_charsets.py b/Tests/test_font_pcf_charsets.py index a1036fd28e6..4477ee29d55 100644 --- a/Tests/test_font_pcf_charsets.py +++ b/Tests/test_font_pcf_charsets.py @@ -101,13 +101,17 @@ def _test_textsize(request, tmp_path, encoding): tempname = save_font(request, tmp_path, encoding) font = ImageFont.load(tempname) for i in range(255): - (dx, dy) = font.getsize(bytearray([i])) + (ox, oy, dx, dy) = font.getbbox(bytearray([i])) + assert ox == 0 + assert oy == 0 assert dy == 20 assert dx in (0, 10) + assert font.getlength(bytearray([i])) == dx message = charsets[encoding]["message"].encode(encoding) for i in range(len(message)): msg = message[: i + 1] - assert font.getsize(msg) == (len(msg) * 10, 20) + assert font.getlength(msg) == len(msg) * 10 + assert font.getbbox(msg) == (0, 0, len(msg) * 10, 20) def test_textsize_iso8859_1(request, tmp_path): From 1bf87556ef9953eeea5751714d87bdcc98b49702 Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 25 May 2022 22:00:13 +0100 Subject: [PATCH 04/19] add textbbox and textlength to ImageDraw2 and update tests --- Tests/test_imagedraw.py | 2 +- Tests/test_imagedraw2.py | 13 +++++++++---- src/PIL/ImageDraw2.py | 26 +++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index dca7bfe6a58..23bc756bb14 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -1239,7 +1239,7 @@ def test_textsize_empty_string(): @skip_unless_feature("freetype2") -def test_textsize_stroke(): +def test_textbbox_stroke(): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) diff --git a/Tests/test_imagedraw2.py b/Tests/test_imagedraw2.py index 3a70176cee5..e4e8a38cb59 100644 --- a/Tests/test_imagedraw2.py +++ b/Tests/test_imagedraw2.py @@ -1,5 +1,7 @@ import os.path +import pytest + from PIL import Image, ImageDraw, ImageDraw2 from .helper import ( @@ -205,7 +207,9 @@ def test_textsize(): font = ImageDraw2.Font("white", FONT_PATH) # Act - size = draw.textsize("ImageDraw2", font) + with pytest.warns(DeprecationWarning) as log: + size = draw.textsize("ImageDraw2", font) + assert len(log) == 1 # Assert assert size[1] == 12 @@ -221,9 +225,10 @@ def test_textsize_empty_string(): # Act # Should not cause 'SystemError: returned NULL without setting an error' - draw.textsize("", font) - draw.textsize("\n", font) - draw.textsize("test\n", font) + draw.textbbox((0, 0), "", font) + draw.textbbox((0, 0), "\n", font) + draw.textbbox((0, 0), "test\n", font) + draw.textlength("", font) @skip_unless_feature("freetype2") diff --git a/src/PIL/ImageDraw2.py b/src/PIL/ImageDraw2.py index 1f63110fd26..6e6a307bde5 100644 --- a/src/PIL/ImageDraw2.py +++ b/src/PIL/ImageDraw2.py @@ -25,6 +25,7 @@ from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath +from ._deprecate import deprecate class Pen: @@ -176,4 +177,27 @@ def textsize(self, text, font): .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textsize` """ - return self.draw.textsize(text, font=font.font) + deprecate("textsize", 10, "textbbox or textlength") + return self.draw.textsize(text, font=font.font, __internal__=True) + + def textbbox(self, xy, text, font): + """ + Returns bounding box (in pixels) of given text. + + :return: ``(left, top, right, bottom)`` bounding box + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textbbox` + """ + if self.transform: + xy = ImagePath.Path(xy) + xy.transform(self.transform) + return self.draw.textbbox(xy, text, font=font.font) + + def textlength(self, text, font): + """ + Returns length (in pixels) of given text. + This is the amount by which following text should be offset. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textlength` + """ + return self.draw.textlength(text, font=font.font) From e2158344a0b4b4016a39dcf40c7220aa77b60579 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 20 Jun 2022 01:20:56 +0100 Subject: [PATCH 05/19] update test_imagefont to use textbbox --- Tests/images/rectangle_surrounding_text.png | Bin 1520 -> 1558 bytes Tests/test_imagefont.py | 126 ++++++++++++++------ Tests/test_imagefontctl.py | 4 +- 3 files changed, 89 insertions(+), 41 deletions(-) diff --git a/Tests/images/rectangle_surrounding_text.png b/Tests/images/rectangle_surrounding_text.png index 2b75a5e9c7ae1fc828125e2903ea6136d52cd2eb..ca77cea7323afb75186315fcd403b7db2509ef86 100644 GIT binary patch delta 1455 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 Date: Mon, 20 Jun 2022 02:18:16 +0100 Subject: [PATCH 06/19] add getbbox and getlength to TransposedFont with tests --- Tests/test_imagefont.py | 39 +++++++++++++++++++++++++++++++++++---- src/PIL/ImageFont.py | 15 +++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index e004edfaff3..606b9ba0ed4 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -315,16 +315,31 @@ def test_rotated_transposed_font(self): # Original font draw.font = font - box_size_a = draw.textsize(word) + with pytest.warns(DeprecationWarning) as log: + box_size_a = draw.textsize(word) + assert len(log) == 1 + bbox_a = draw.textbbox((10, 10), word) # Rotated font draw.font = transposed_font - box_size_b = draw.textsize(word) + with pytest.warns(DeprecationWarning) as log: + box_size_b = draw.textsize(word) + assert len(log) == 1 + bbox_b = draw.textbbox((20, 20), word) # Check (w,h) of box a is (h,w) of box b assert box_size_a[0] == box_size_b[1] assert box_size_a[1] == box_size_b[0] + # Check bbox b is (20, 20, 20 + h, 20 + w) + assert bbox_b[0] == 20 + assert bbox_b[1] == 20 + assert bbox_b[2] == 20 + bbox_a[3] - bbox_a[1] + assert bbox_b[3] == 20 + bbox_a[2] - bbox_a[0] + + # text length is undefined for vertical text + pytest.raises(ValueError, draw.textlength, word) + def test_unrotated_transposed_font(self): img_grey = Image.new("L", (100, 100)) draw = ImageDraw.Draw(img_grey) @@ -336,15 +351,31 @@ def test_unrotated_transposed_font(self): # Original font draw.font = font - box_size_a = draw.textsize(word) + with pytest.warns(DeprecationWarning) as log: + box_size_a = draw.textsize(word) + assert len(log) == 1 + bbox_a = draw.textbbox((10, 10), word) + length_a = draw.textlength(word) # Rotated font draw.font = transposed_font - box_size_b = draw.textsize(word) + with pytest.warns(DeprecationWarning) as log: + box_size_b = draw.textsize(word) + assert len(log) == 1 + bbox_b = draw.textbbox((20, 20), word) + length_b = draw.textlength(word) # Check boxes a and b are same size assert box_size_a == box_size_b + # Check bbox b is (20, 20, 20 + w, 20 + h) + assert bbox_b[0] == 20 + assert bbox_b[1] == 20 + assert bbox_b[2] == 20 + bbox_a[2] - bbox_a[0] + assert bbox_b[3] == 20 + bbox_a[3] - bbox_a[1] + + assert length_a == length_b + def test_rotated_transposed_font_get_mask(self): # Arrange text = "mask this" diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 4e2cb9686df..ef452778266 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -853,6 +853,21 @@ def getmask(self, text, mode="", *args, **kwargs): return im.transpose(self.orientation) return im + def getbbox(self, text, *args, **kwargs): + # TransposedFont doesn't support getmask2, move top-left point to (0, 0) + # this has no effect on ImageFont and simulates anchor="lt" for FreeTypeFont + left, top, right, bottom = self.font.getbbox(text, *args, **kwargs) + width = right - left + height = bottom - top + if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): + return 0, 0, height, width + return 0, 0, width, height + + def getlength(self, text, *args, **kwargs): + if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): + raise ValueError("text length is undefined for rotated text") + return self.font.getlength(text, *args, **kwargs) + def load(filename): """ From a7baa31de854723ddfe0d08d472196feb0e8acc3 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 20 Jun 2022 02:49:26 +0100 Subject: [PATCH 07/19] use getbbox instead of getsize in fuzzers.py --- Tests/oss-fuzz/fuzzers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/oss-fuzz/fuzzers.py b/Tests/oss-fuzz/fuzzers.py index 5786764a64d..10a172b4675 100644 --- a/Tests/oss-fuzz/fuzzers.py +++ b/Tests/oss-fuzz/fuzzers.py @@ -33,9 +33,9 @@ def fuzz_font(data): # different font objects. return - font.getsize_multiline("ABC\nAaaa") + font.getbbox("ABC") font.getmask("test text") with Image.new(mode="RGBA", size=(200, 200)) as im: draw = ImageDraw.Draw(im) - draw.multiline_textsize("ABC\nAaaa", font, stroke_width=2) + draw.multiline_textbbox((10, 10), "ABC\nAaaa", font, stroke_width=2) draw.text((10, 10), "Test Text", font=font, fill="#000") From f57a9d678c770712320345ed9f71c04b38db1249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ondrej=20Baranovi=C4=8D?= Date: Thu, 30 Jun 2022 14:20:56 +0200 Subject: [PATCH 08/19] update TransposedFont.getlength error message Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- src/PIL/ImageFont.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index ef452778266..77d2cf0f9da 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -865,7 +865,7 @@ def getbbox(self, text, *args, **kwargs): def getlength(self, text, *args, **kwargs): if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): - raise ValueError("text length is undefined for rotated text") + raise ValueError("text length is undefined for text rotated by 90 or 270 degrees") return self.font.getlength(text, *args, **kwargs) From 303ec1a95e8091c1fa3c0a11da7e8603c55e6a69 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 30 Jun 2022 12:21:39 +0000 Subject: [PATCH 09/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/PIL/ImageFont.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 77d2cf0f9da..8a55d517fdc 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -865,7 +865,9 @@ def getbbox(self, text, *args, **kwargs): def getlength(self, text, *args, **kwargs): if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): - raise ValueError("text length is undefined for text rotated by 90 or 270 degrees") + raise ValueError( + "text length is undefined for text rotated by 90 or 270 degrees" + ) return self.font.getlength(text, *args, **kwargs) From 838b1f1598f5f7c110874a5341dd01aba611ddd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ondrej=20Baranovi=C4=8D?= Date: Thu, 30 Jun 2022 14:22:07 +0200 Subject: [PATCH 10/19] add replacement for getsize_multiline to deprecation warning --- src/PIL/ImageFont.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 8a55d517fdc..0bd92749d58 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -532,7 +532,7 @@ def getsize_multiline( :return: (width, height) """ - deprecate("getsize_multiline", 10) + deprecate("getsize_multiline", 10, "ImageDraw.multiline_textbbox") max_width = 0 lines = self._multiline_split(text) line_spacing = ( From 3c0b8763abb26232bf304a5cdf2b046d5f7e443e Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 30 Jun 2022 21:58:47 +1000 Subject: [PATCH 11/19] Added documentation and release notes --- docs/deprecations.rst | 16 ++++++++++++++++ docs/reference/ImageFont.rst | 1 + docs/releasenotes/9.2.0.rst | 16 ++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 8c5b8a748d7..af9c35f34a4 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -178,6 +178,22 @@ Image.coerce_e This undocumented method has been deprecated and will be removed in Pillow 10 (2023-07-01). +Font size and offset methods +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. deprecated:: 9.2.0 + +=========================================================================== ============================================================================================================= +Deprecated Use instead +=========================================================================== ============================================================================================================= +:py:meth:`.FreeTypeFont.getsize` and :py:meth:`.FreeTypeFont.getoffset` :py:meth:`.FreeTypeFont.getbbox` and :py:meth:`.FreeTypeFont.getlength` +:py:meth:`.FreeTypeFont.getsize_multiline` :py:meth:`.ImageDraw.multiline_textbbox` +:py:meth:`.ImageFont.getsize` :py:meth:`.ImageFont.getbbox` and :py:meth:`.ImageFont.getlength` +:py:meth:`.TransposedFont.getsize` :py:meth:`.TransposedFont.getbbox` and :py:meth:`.TransposedFont.getlength` +:py:meth:`.ImageDraw.textsize` and :py:meth:`.ImageDraw.multiline_textsize` :py:meth:`.ImageDraw.textbbox`, :py:meth:`.ImageDraw.textlength` and :py:meth:`.ImageDraw.multiline_textbbox` +``ImageDraw2.Draw().textsize`` ``ImageDraw2.Draw().textbbox`` and ``ImageDraw2.Draw().textlength`` +=========================================================================== ============================================================================================================= + Removed features ---------------- diff --git a/docs/reference/ImageFont.rst b/docs/reference/ImageFont.rst index 8efef7cfd5c..516fa63a783 100644 --- a/docs/reference/ImageFont.rst +++ b/docs/reference/ImageFont.rst @@ -56,6 +56,7 @@ Methods .. autoclass:: PIL.ImageFont.TransposedFont :members: + :undoc-members: Constants --------- diff --git a/docs/releasenotes/9.2.0.rst b/docs/releasenotes/9.2.0.rst index ca52f6ab952..8815e2c0d61 100644 --- a/docs/releasenotes/9.2.0.rst +++ b/docs/releasenotes/9.2.0.rst @@ -40,6 +40,22 @@ Image.coerce_e This undocumented method has been deprecated and will be removed in Pillow 10 (2023-07-01). +Font size and offset methods +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. deprecated:: 9.2.0 + +=========================================================================== ============================================================================================================= +Deprecated Use instead +=========================================================================== ============================================================================================================= +:py:meth:`.FreeTypeFont.getsize` and :py:meth:`.FreeTypeFont.getoffset` :py:meth:`.FreeTypeFont.getbbox` and :py:meth:`.FreeTypeFont.getlength` +:py:meth:`.FreeTypeFont.getsize_multiline` :py:meth:`.ImageDraw.multiline_textbbox` +:py:meth:`.ImageFont.getsize` :py:meth:`.ImageFont.getbbox` and :py:meth:`.ImageFont.getlength` +:py:meth:`.TransposedFont.getsize` :py:meth:`.TransposedFont.getbbox` and :py:meth:`.TransposedFont.getlength` +:py:meth:`.ImageDraw.textsize` and :py:meth:`.ImageDraw.multiline_textsize` :py:meth:`.ImageDraw.textbbox`, :py:meth:`.ImageDraw.textlength` and :py:meth:`.ImageDraw.multiline_textbbox` +``ImageDraw2.Draw().textsize`` ``ImageDraw2.Draw().textbbox`` and ``ImageDraw2.Draw().textlength`` +=========================================================================== ============================================================================================================= + API Additions ============= From 9957e0b0d7371685abcc68f6d591277d26348fc9 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 30 Jun 2022 14:38:20 +0200 Subject: [PATCH 12/19] link to ImageDraw2 in deprecations and release notes --- docs/deprecations.rst | 2 +- docs/releasenotes/9.2.0.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index af9c35f34a4..3796e3dfbeb 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -191,7 +191,7 @@ Deprecated Use :py:meth:`.ImageFont.getsize` :py:meth:`.ImageFont.getbbox` and :py:meth:`.ImageFont.getlength` :py:meth:`.TransposedFont.getsize` :py:meth:`.TransposedFont.getbbox` and :py:meth:`.TransposedFont.getlength` :py:meth:`.ImageDraw.textsize` and :py:meth:`.ImageDraw.multiline_textsize` :py:meth:`.ImageDraw.textbbox`, :py:meth:`.ImageDraw.textlength` and :py:meth:`.ImageDraw.multiline_textbbox` -``ImageDraw2.Draw().textsize`` ``ImageDraw2.Draw().textbbox`` and ``ImageDraw2.Draw().textlength`` +:py:meth:`.ImageDraw2.Draw.textsize` :py:meth:`.ImageDraw2.Draw.textbbox` and :py:meth:`.ImageDraw2.Draw.textlength` =========================================================================== ============================================================================================================= Removed features diff --git a/docs/releasenotes/9.2.0.rst b/docs/releasenotes/9.2.0.rst index 8815e2c0d61..bd6b767e777 100644 --- a/docs/releasenotes/9.2.0.rst +++ b/docs/releasenotes/9.2.0.rst @@ -53,7 +53,7 @@ Deprecated Use :py:meth:`.ImageFont.getsize` :py:meth:`.ImageFont.getbbox` and :py:meth:`.ImageFont.getlength` :py:meth:`.TransposedFont.getsize` :py:meth:`.TransposedFont.getbbox` and :py:meth:`.TransposedFont.getlength` :py:meth:`.ImageDraw.textsize` and :py:meth:`.ImageDraw.multiline_textsize` :py:meth:`.ImageDraw.textbbox`, :py:meth:`.ImageDraw.textlength` and :py:meth:`.ImageDraw.multiline_textbbox` -``ImageDraw2.Draw().textsize`` ``ImageDraw2.Draw().textbbox`` and ``ImageDraw2.Draw().textlength`` +:py:meth:`.ImageDraw2.Draw.textsize` :py:meth:`.ImageDraw2.Draw.textbbox` and :py:meth:`.ImageDraw2.Draw.textlength` =========================================================================== ============================================================================================================= API Additions From 7691231aa7bb74584139c8c50b60e93d56790f14 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 30 Jun 2022 14:51:29 +0200 Subject: [PATCH 13/19] Fix heading in deprecations.rst --- docs/deprecations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 3796e3dfbeb..a0289bb24f2 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -179,7 +179,7 @@ This undocumented method has been deprecated and will be removed in Pillow 10 (2023-07-01). Font size and offset methods -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. deprecated:: 9.2.0 From 65020e7c7c4539e905b3f5a9a1666892ac41ed70 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 30 Jun 2022 22:40:40 +1000 Subject: [PATCH 14/19] Documented deprecation in individual methods --- docs/reference/ImageDraw.rst | 4 ++++ src/PIL/ImageDraw2.py | 2 ++ src/PIL/ImageFont.py | 11 +++++++++++ 3 files changed, 17 insertions(+) diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index b95d8d591a7..1ba024eea9d 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -436,6 +436,8 @@ Methods .. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) + .. deprecated:: 9.2.0 + Return the size of the given string, in pixels. Use :py:meth:`textlength()` to measure the offset of following text with @@ -484,6 +486,8 @@ Methods .. py:method:: ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) + .. deprecated:: 9.2.0 + Return the size of the given string, in pixels. Use :py:meth:`textlength()` to measure the offset of following text with diff --git a/src/PIL/ImageDraw2.py b/src/PIL/ImageDraw2.py index 6e6a307bde5..ea9461e92ec 100644 --- a/src/PIL/ImageDraw2.py +++ b/src/PIL/ImageDraw2.py @@ -173,6 +173,8 @@ def text(self, xy, text, font): def textsize(self, text, font): """ + .. deprecated:: 9.2.0 + Return the size of the given string, in pixels. .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textsize` diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 0bd92749d58..1f356adefd9 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -137,6 +137,8 @@ def _load_pilfont_data(self, file, image): def getsize(self, text, *args, **kwargs): """ + .. deprecated:: 9.2.0 + Returns width and height (in pixels) of given text. :param text: Text to measure. @@ -424,6 +426,8 @@ def getsize( __internal__=False, ): """ + .. deprecated:: 9.2.0 + Returns width and height (in pixels) of given text if rendered in font with provided direction, features, and language. @@ -493,6 +497,8 @@ def getsize_multiline( stroke_width=0, ): """ + .. deprecated:: 9.2.0 + Returns width and height (in pixels) of given text if rendered in font with provided direction, features, and language, while respecting newline characters. @@ -548,6 +554,8 @@ def getsize_multiline( def getoffset(self, text): """ + .. deprecated:: 9.2.0 + Returns the offset of given text. This is the gap between the starting coordinate and the first marking. Note that this gap is included in the result of :py:func:`~PIL.ImageFont.FreeTypeFont.getsize`. @@ -837,6 +845,9 @@ def __init__(self, font, orientation=None): self.orientation = orientation # any 'transpose' argument, or None def getsize(self, text, *args, **kwargs): + """ + .. deprecated:: 9.2.0 + """ if not kwargs.get("__internal__"): deprecate("getsize", 10, "getbbox or getlength") try: From ad5271d62f65deb67b10c1938fff782e68ab3e62 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 30 Jun 2022 15:02:09 +0200 Subject: [PATCH 15/19] Document replacements for individual deprecated font methods --- docs/reference/ImageDraw.rst | 8 ++++---- src/PIL/ImageFont.py | 11 +++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index 1ba024eea9d..e6e2d15c06b 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -437,13 +437,12 @@ Methods .. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) .. deprecated:: 9.2.0 + Use :py:meth:`textlength()` to measure the offset of following text with + 1/64 pixel precision. + Use :py:meth:`textbbox()` to get the exact bounding box based on an anchor. Return the size of the given string, in pixels. - Use :py:meth:`textlength()` to measure the offset of following text with - 1/64 pixel precision. - Use :py:meth:`textbbox()` to get the exact bounding box based on an anchor. - .. note:: For historical reasons this function measures text height from the ascender line instead of the top, see :ref:`text-anchors`. If you wish to measure text height from the top, it is recommended @@ -487,6 +486,7 @@ Methods .. py:method:: ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) .. deprecated:: 9.2.0 + Use :py:meth:`.multiline_textbbox` instead. Return the size of the given string, in pixels. diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 1f356adefd9..8c23b59b6be 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -138,6 +138,7 @@ def _load_pilfont_data(self, file, image): def getsize(self, text, *args, **kwargs): """ .. deprecated:: 9.2.0 + Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. Returns width and height (in pixels) of given text. @@ -427,14 +428,13 @@ def getsize( ): """ .. deprecated:: 9.2.0 + Use :py:meth:`getlength()` to measure the offset of following text with + 1/64 pixel precision. + Use :py:meth:`getbbox()` to get the exact bounding box based on an anchor. Returns width and height (in pixels) of given text if rendered in font with provided direction, features, and language. - Use :py:meth:`getlength()` to measure the offset of following text with - 1/64 pixel precision. - Use :py:meth:`getbbox()` to get the exact bounding box based on an anchor. - .. note:: For historical reasons this function measures text height from the ascender line instead of the top, see :ref:`text-anchors`. If you wish to measure text height from the top, it is recommended @@ -498,6 +498,7 @@ def getsize_multiline( ): """ .. deprecated:: 9.2.0 + Use :py:meth:`.ImageDraw.multiline_textbbox` instead. Returns width and height (in pixels) of given text if rendered in font with provided direction, features, and language, while respecting @@ -555,6 +556,7 @@ def getsize_multiline( def getoffset(self, text): """ .. deprecated:: 9.2.0 + Use :py:meth:`.getbbox` instead. Returns the offset of given text. This is the gap between the starting coordinate and the first marking. Note that this gap is @@ -847,6 +849,7 @@ def __init__(self, font, orientation=None): def getsize(self, text, *args, **kwargs): """ .. deprecated:: 9.2.0 + Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. """ if not kwargs.get("__internal__"): deprecate("getsize", 10, "getbbox or getlength") From a37c21e136fbd0398a9f767b0cc7ac910ce67daf Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 30 Jun 2022 15:29:09 +0200 Subject: [PATCH 16/19] document planned removal date for ImageFont deprecations and release notes --- docs/deprecations.rst | 3 +++ docs/releasenotes/9.2.0.rst | 3 +++ 2 files changed, 6 insertions(+) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index a0289bb24f2..9be92770ab9 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -183,6 +183,9 @@ Font size and offset methods .. deprecated:: 9.2.0 +Several functions for computing the size and offset of rendered text +have been deprecated and will be removed in Pillow 10 (2023-07-01): + =========================================================================== ============================================================================================================= Deprecated Use instead =========================================================================== ============================================================================================================= diff --git a/docs/releasenotes/9.2.0.rst b/docs/releasenotes/9.2.0.rst index bd6b767e777..9c102f1776a 100644 --- a/docs/releasenotes/9.2.0.rst +++ b/docs/releasenotes/9.2.0.rst @@ -45,6 +45,9 @@ Font size and offset methods .. deprecated:: 9.2.0 +Several functions for computing the size and offset of rendered text +have been deprecated and will be removed in Pillow 10 (2023-07-01): + =========================================================================== ============================================================================================================= Deprecated Use instead =========================================================================== ============================================================================================================= From 74e0b954f2010b0e2e19166b1defad2f4ed6307c Mon Sep 17 00:00:00 2001 From: nulano Date: Fri, 1 Jul 2022 11:22:47 +0200 Subject: [PATCH 17/19] test {ImageFont,TransposedFont}.getsize() deprecation --- Tests/test_font_pcf.py | 3 +++ Tests/test_imagefont.py | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Tests/test_font_pcf.py b/Tests/test_font_pcf.py index 815ef1d9254..c217378fb74 100644 --- a/Tests/test_font_pcf.py +++ b/Tests/test_font_pcf.py @@ -82,6 +82,9 @@ def test_textsize(request, tmp_path): assert dy == 20 assert dx in (0, 10) assert font.getlength(chr(i)) == dx + with pytest.warns(DeprecationWarning) as log: + assert font.getsize(chr(i)) == (dx, dy) + assert len(log) == 1 for i in range(len(message)): msg = message[: i + 1] assert font.getlength(msg) == len(msg) * 10 diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 606b9ba0ed4..16da87d469a 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -317,14 +317,16 @@ def test_rotated_transposed_font(self): draw.font = font with pytest.warns(DeprecationWarning) as log: box_size_a = draw.textsize(word) - assert len(log) == 1 + assert box_size_a == font.getsize(word) + assert len(log) == 2 bbox_a = draw.textbbox((10, 10), word) # Rotated font draw.font = transposed_font with pytest.warns(DeprecationWarning) as log: box_size_b = draw.textsize(word) - assert len(log) == 1 + assert box_size_b == transposed_font.getsize(word) + assert len(log) == 2 bbox_b = draw.textbbox((20, 20), word) # Check (w,h) of box a is (h,w) of box b From 729fe6f8b0ec7ebea408c526d4c3f8c998c7e6bb Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 1 Jul 2022 19:45:36 +1000 Subject: [PATCH 18/19] Updated indentation --- docs/reference/ImageDraw.rst | 10 ++++++---- src/PIL/ImageFont.py | 19 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index e6e2d15c06b..c2d72c804c1 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -437,9 +437,10 @@ Methods .. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) .. deprecated:: 9.2.0 - Use :py:meth:`textlength()` to measure the offset of following text with - 1/64 pixel precision. - Use :py:meth:`textbbox()` to get the exact bounding box based on an anchor. + + Use :py:meth:`textlength()` to measure the offset of following text with + 1/64 pixel precision. + Use :py:meth:`textbbox()` to get the exact bounding box based on an anchor. Return the size of the given string, in pixels. @@ -486,7 +487,8 @@ Methods .. py:method:: ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) .. deprecated:: 9.2.0 - Use :py:meth:`.multiline_textbbox` instead. + + Use :py:meth:`.multiline_textbbox` instead. Return the size of the given string, in pixels. diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 8c23b59b6be..1f62468ab3b 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -138,7 +138,8 @@ def _load_pilfont_data(self, file, image): def getsize(self, text, *args, **kwargs): """ .. deprecated:: 9.2.0 - Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. + + Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. Returns width and height (in pixels) of given text. @@ -428,9 +429,10 @@ def getsize( ): """ .. deprecated:: 9.2.0 - Use :py:meth:`getlength()` to measure the offset of following text with - 1/64 pixel precision. - Use :py:meth:`getbbox()` to get the exact bounding box based on an anchor. + + Use :py:meth:`getlength()` to measure the offset of following text with + 1/64 pixel precision. + Use :py:meth:`getbbox()` to get the exact bounding box based on an anchor. Returns width and height (in pixels) of given text if rendered in font with provided direction, features, and language. @@ -498,7 +500,8 @@ def getsize_multiline( ): """ .. deprecated:: 9.2.0 - Use :py:meth:`.ImageDraw.multiline_textbbox` instead. + + Use :py:meth:`.ImageDraw.multiline_textbbox` instead. Returns width and height (in pixels) of given text if rendered in font with provided direction, features, and language, while respecting @@ -556,7 +559,8 @@ def getsize_multiline( def getoffset(self, text): """ .. deprecated:: 9.2.0 - Use :py:meth:`.getbbox` instead. + + Use :py:meth:`.getbbox` instead. Returns the offset of given text. This is the gap between the starting coordinate and the first marking. Note that this gap is @@ -849,7 +853,8 @@ def __init__(self, font, orientation=None): def getsize(self, text, *args, **kwargs): """ .. deprecated:: 9.2.0 - Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. + + Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. """ if not kwargs.get("__internal__"): deprecate("getsize", 10, "getbbox or getlength") From 8a6050ee5bef46f3c77688023d21b680d74b8af2 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 1 Jul 2022 20:33:59 +1000 Subject: [PATCH 19/19] Replaced __internal__ argument with warning filters --- src/PIL/ImageDraw.py | 102 +++++++++++++++++++++--------------------- src/PIL/ImageDraw2.py | 6 ++- src/PIL/ImageFont.py | 31 ++++++------- 3 files changed, 70 insertions(+), 69 deletions(-) diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index 723ec17fdc1..8970471d3b2 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -32,6 +32,7 @@ import math import numbers +import warnings from . import Image, ImageColor from ._deprecate import deprecate @@ -375,15 +376,16 @@ def _multiline_split(self, text): def _multiline_spacing(self, font, spacing, stroke_width): # this can be replaced with self.textbbox(...)[3] when textsize is removed - return ( - self.textsize( - "A", - font=font, - stroke_width=stroke_width, - __internal__=True, - )[1] - + spacing - ) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + return ( + self.textsize( + "A", + font=font, + stroke_width=stroke_width, + )[1] + + spacing + ) def text( self, @@ -582,34 +584,34 @@ def textsize( features=None, language=None, stroke_width=0, - __internal__=False, ): """Get the size of a given string, in pixels.""" - if not __internal__: - deprecate("textsize", 10, "textbbox or textlength") + deprecate("textsize", 10, "textbbox or textlength") if self._multiline_check(text): - return self.multiline_textsize( + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + return self.multiline_textsize( + text, + font, + spacing, + direction, + features, + language, + stroke_width, + ) + + if font is None: + font = self.getfont() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + return font.getsize( text, - font, - spacing, direction, features, language, stroke_width, - __internal__=True, ) - if font is None: - font = self.getfont() - return font.getsize( - text, - direction, - features, - language, - stroke_width, - __internal__=True, - ) - def multiline_textsize( self, text, @@ -619,25 +621,24 @@ def multiline_textsize( features=None, language=None, stroke_width=0, - __internal__=False, ): - if not __internal__: - deprecate("multiline_textsize", 10, "multiline_textbbox") + deprecate("multiline_textsize", 10, "multiline_textbbox") max_width = 0 lines = self._multiline_split(text) line_spacing = self._multiline_spacing(font, spacing, stroke_width) - for line in lines: - line_width, line_height = self.textsize( - line, - font, - spacing, - direction, - features, - language, - stroke_width, - __internal__=True, - ) - max_width = max(max_width, line_width) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + for line in lines: + line_width, line_height = self.textsize( + line, + font, + spacing, + direction, + features, + language, + stroke_width, + ) + max_width = max(max_width, line_width) return max_width, len(lines) * line_spacing - spacing def textlength( @@ -662,14 +663,15 @@ def textlength( return font.getlength(text, mode, direction, features, language) except AttributeError: deprecate("textlength support for fonts without getlength", 10) - size = self.textsize( - text, - font, - direction=direction, - features=features, - language=language, - __internal__=True, - ) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + size = self.textsize( + text, + font, + direction=direction, + features=features, + language=language, + ) if direction == "ttb": return size[1] return size[0] diff --git a/src/PIL/ImageDraw2.py b/src/PIL/ImageDraw2.py index ea9461e92ec..2667b77dd43 100644 --- a/src/PIL/ImageDraw2.py +++ b/src/PIL/ImageDraw2.py @@ -24,6 +24,8 @@ """ +import warnings + from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath from ._deprecate import deprecate @@ -180,7 +182,9 @@ def textsize(self, text, font): .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textsize` """ deprecate("textsize", 10, "textbbox or textlength") - return self.draw.textsize(text, font=font.font, __internal__=True) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + return self.draw.textsize(text, font=font.font) def textbbox(self, xy, text, font): """ diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 1f62468ab3b..a3b711c6077 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -147,8 +147,7 @@ def getsize(self, text, *args, **kwargs): :return: (width, height) """ - if not kwargs.get("__internal__"): - deprecate("getsize", 10, "getbbox or getlength") + deprecate("getsize", 10, "getbbox or getlength") return self.font.getsize(text) def getmask(self, text, mode="", *args, **kwargs): @@ -425,7 +424,6 @@ def getsize( features=None, language=None, stroke_width=0, - __internal__=False, ): """ .. deprecated:: 9.2.0 @@ -479,8 +477,7 @@ def getsize( :return: (width, height) """ - if not __internal__: - deprecate("getsize", 10, "getbbox or getlength") + deprecate("getsize", 10, "getbbox or getlength") # vertical offset is added for historical reasons # see https://github.com/python-pillow/Pillow/pull/4910#discussion_r486682929 size, offset = self.font.getsize(text, "L", direction, features, language) @@ -545,14 +542,14 @@ def getsize_multiline( deprecate("getsize_multiline", 10, "ImageDraw.multiline_textbbox") max_width = 0 lines = self._multiline_split(text) - line_spacing = ( - self.getsize("A", stroke_width=stroke_width, __internal__=True)[1] + spacing - ) - for line in lines: - line_width, line_height = self.getsize( - line, direction, features, language, stroke_width, __internal__=True - ) - max_width = max(max_width, line_width) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + line_spacing = self.getsize("A", stroke_width=stroke_width)[1] + spacing + for line in lines: + line_width, line_height = self.getsize( + line, direction, features, language, stroke_width + ) + max_width = max(max_width, line_width) return max_width, len(lines) * line_spacing - spacing @@ -856,11 +853,9 @@ def getsize(self, text, *args, **kwargs): Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. """ - if not kwargs.get("__internal__"): - deprecate("getsize", 10, "getbbox or getlength") - try: - w, h = self.font.getsize(text, __internal__=True) - except TypeError: + deprecate("getsize", 10, "getbbox or getlength") + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) w, h = self.font.getsize(text) if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): return h, w