From b2301d70d104f36a08ae658f569d02f7796fc8fa Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 5 Apr 2023 19:10:51 +1000 Subject: [PATCH] Removed ImageFont.getsize and related functions --- Tests/images/imagedraw_stroke_multiline.png | Bin 4061 -> 4059 bytes Tests/test_deprecate.py | 19 +- Tests/test_font_pcf.py | 3 - Tests/test_imagedraw.py | 19 +- Tests/test_imagedraw2.py | 16 -- Tests/test_imagefont.py | 95 +--------- docs/deprecations.rst | 98 +++++----- docs/releasenotes/10.0.0.rst | 16 ++ docs/releasenotes/9.2.0.rst | 20 +- src/PIL/ImageDraw.py | 97 +--------- src/PIL/ImageDraw2.py | 16 -- src/PIL/ImageFont.py | 193 -------------------- src/PIL/_deprecate.py | 2 - 13 files changed, 96 insertions(+), 498 deletions(-) diff --git a/Tests/images/imagedraw_stroke_multiline.png b/Tests/images/imagedraw_stroke_multiline.png index fc5e07c8679d5aa12a1d95152ea6d2542f169697..c290fc0568e5c4b40299a208cde7d0d760077fd0 100644 GIT binary patch delta 3993 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 delta 3990 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 waL7gnG#ZUYqtR$Ik*ODxum}VhG*>` for more information. - - Returns width and height (in pixels) of given text. - - :param text: Text to measure. - - :return: (width, height) - """ - deprecate("getsize", 10, "getbbox or getlength") - return self.font.getsize(text) - def getmask(self, text, mode="", *args, **kwargs): """ Create a bitmap for the text. @@ -398,165 +380,6 @@ class FreeTypeFont: width, height = size[0] + 2 * stroke_width, size[1] + 2 * stroke_width return left, top, left + width, top + height - def getsize( - self, - text, - direction=None, - features=None, - language=None, - stroke_width=0, - ): - """ - .. 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. - - See :ref:`deprecations ` for more information. - - Returns width and height (in pixels) of given text if rendered in font with - provided direction, features, and language. - - .. 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 - to use the bottom value of :meth:`getbbox` with ``anchor='lt'`` instead. - - :param text: Text to measure. - - :param direction: Direction of the text. It can be 'rtl' (right to - left), 'ltr' (left to right) or 'ttb' (top to bottom). - Requires libraqm. - - .. versionadded:: 4.2.0 - - :param features: A list of OpenType font features to be used during text - layout. This is usually used to turn on optional - font features that are not enabled by default, - for example 'dlig' or 'ss01', but can be also - used to turn off default font features for - example '-liga' to disable ligatures or '-kern' - to disable kerning. To get all supported - features, see - https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist - Requires libraqm. - - .. versionadded:: 4.2.0 - - :param language: Language of the text. Different languages may use - different glyph shapes or ligatures. This parameter tells - the font which language the text is in, and to apply the - correct substitutions as appropriate, if available. - It should be a `BCP 47 language code - `_ - Requires libraqm. - - .. versionadded:: 6.0.0 - - :param stroke_width: The width of the text stroke. - - .. versionadded:: 6.2.0 - - :return: (width, height) - """ - 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) - return ( - size[0] + stroke_width * 2, - size[1] + stroke_width * 2 + offset[1], - ) - - def getsize_multiline( - self, - text, - direction=None, - spacing=4, - features=None, - language=None, - stroke_width=0, - ): - """ - .. deprecated:: 9.2.0 - - Use :py:meth:`.ImageDraw.multiline_textbbox` instead. - - See :ref:`deprecations ` for more information. - - Returns width and height (in pixels) of given text if rendered in font - with provided direction, features, and language, while respecting - newline characters. - - :param text: Text to measure. - - :param direction: Direction of the text. It can be 'rtl' (right to - left), 'ltr' (left to right) or 'ttb' (top to bottom). - Requires libraqm. - - :param spacing: The vertical gap between lines, defaulting to 4 pixels. - - :param features: A list of OpenType font features to be used during text - layout. This is usually used to turn on optional - font features that are not enabled by default, - for example 'dlig' or 'ss01', but can be also - used to turn off default font features for - example '-liga' to disable ligatures or '-kern' - to disable kerning. To get all supported - features, see - https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist - Requires libraqm. - - :param language: Language of the text. Different languages may use - different glyph shapes or ligatures. This parameter tells - the font which language the text is in, and to apply the - correct substitutions as appropriate, if available. - It should be a `BCP 47 language code - `_ - Requires libraqm. - - .. versionadded:: 6.0.0 - - :param stroke_width: The width of the text stroke. - - .. versionadded:: 6.2.0 - - :return: (width, height) - """ - deprecate("getsize_multiline", 10, "ImageDraw.multiline_textbbox") - max_width = 0 - lines = self._multiline_split(text) - 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 - - def getoffset(self, text): - """ - .. deprecated:: 9.2.0 - - Use :py:meth:`.getbbox` instead. - - See :ref:`deprecations ` for more information. - - 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`. - - :param text: Text to measure. - - :return: A tuple of the x and y offset - """ - deprecate("getoffset", 10, "getbbox") - return self.font.getsize(text)[1] - def getmask( self, text, @@ -851,22 +674,6 @@ class TransposedFont: self.font = font self.orientation = orientation # any 'transpose' argument, or None - def getsize(self, text, *args, **kwargs): - """ - .. deprecated:: 9.2.0 - - Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead. - - See :ref:`deprecations ` for more information. - """ - 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 - return w, h - def getmask(self, text, mode="", *args, **kwargs): im = self.font.getmask(text, mode, *args, **kwargs) if self.orientation is not None: diff --git a/src/PIL/_deprecate.py b/src/PIL/_deprecate.py index 81f2189dc..2f2a3df13 100644 --- a/src/PIL/_deprecate.py +++ b/src/PIL/_deprecate.py @@ -45,8 +45,6 @@ def deprecate( elif when <= int(__version__.split(".")[0]): msg = f"{deprecated} {is_} deprecated and should be removed." raise RuntimeError(msg) - elif when == 10: - removed = "Pillow 10 (2023-07-01)" elif when == 11: removed = "Pillow 11 (2024-10-15)" else: