diff --git a/Tests/images/multiline_text.png b/Tests/images/multiline_text.png index ff1308c5ef2..e39c6586ca5 100644 Binary files a/Tests/images/multiline_text.png and b/Tests/images/multiline_text.png differ diff --git a/Tests/images/multiline_text_center.png b/Tests/images/multiline_text_center.png index f44d0783a09..837c6382a97 100644 Binary files a/Tests/images/multiline_text_center.png and b/Tests/images/multiline_text_center.png differ diff --git a/Tests/images/multiline_text_right.png b/Tests/images/multiline_text_right.png index 1b32d916754..58b3bdddd87 100644 Binary files a/Tests/images/multiline_text_right.png and b/Tests/images/multiline_text_right.png differ diff --git a/Tests/images/multiline_text_spacing.png b/Tests/images/multiline_text_spacing.png index 3c3bc0f267d..3b367c7ddee 100644 Binary files a/Tests/images/multiline_text_spacing.png and b/Tests/images/multiline_text_spacing.png differ diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 6f7646cb08d..3ed3a2f025d 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -155,7 +155,6 @@ def test_textsize_equal(self): draw.text((10, 10), txt, font=ttf) draw.rectangle((10, 10, 10 + size[0], 10 + size[1])) - # Epsilon ~.5 fails with FreeType 2.7 assert_image_similar_tofile( im, "Tests/images/rectangle_surrounding_text.png", 2.5 ) @@ -216,8 +215,7 @@ def test_render_multiline_text(self): draw = ImageDraw.Draw(im) draw.text((0, 0), TEST_TEXT, font=ttf) - # Epsilon ~.5 fails with FreeType 2.7 - assert_image_similar_tofile(im, "Tests/images/multiline_text.png", 6.2) + assert_image_similar_tofile(im, "Tests/images/multiline_text.png", 0.01) # Test that text() can pass on additional arguments # to multiline_text() @@ -232,9 +230,8 @@ def test_render_multiline_text(self): draw = ImageDraw.Draw(im) draw.multiline_text((0, 0), TEST_TEXT, font=ttf, align=align) - # Epsilon ~.5 fails with FreeType 2.7 assert_image_similar_tofile( - im, "Tests/images/multiline_text" + ext + ".png", 6.2 + im, "Tests/images/multiline_text" + ext + ".png", 0.01 ) def test_unknown_align(self): @@ -289,8 +286,7 @@ def test_multiline_spacing(self): draw = ImageDraw.Draw(im) draw.multiline_text((0, 0), TEST_TEXT, font=ttf, spacing=10) - # Epsilon ~.5 fails with FreeType 2.7 - assert_image_similar_tofile(im, "Tests/images/multiline_text_spacing.png", 6.2) + assert_image_similar_tofile(im, "Tests/images/multiline_text_spacing.png", 2.5) def test_rotated_transposed_font(self): img_grey = Image.new("L", (100, 100)) @@ -738,30 +734,26 @@ def test_textbbox_non_freetypefont(self): d.textbbox((0, 0), "test", font=default_font) @pytest.mark.parametrize( - "anchor, left, left_old, top", + "anchor, left, top", ( # test horizontal anchors - ("ls", 0, 0, -36), - ("ms", -64, -65, -36), - ("rs", -128, -129, -36), + ("ls", 0, -36), + ("ms", -64, -36), + ("rs", -128, -36), # test vertical anchors - ("ma", -64, -65, 16), - ("mt", -64, -65, 0), - ("mm", -64, -65, -17), - ("mb", -64, -65, -44), - ("md", -64, -65, -51), + ("ma", -64, 16), + ("mt", -64, 0), + ("mm", -64, -17), + ("mb", -64, -44), + ("md", -64, -51), ), ids=("ls", "ms", "rs", "ma", "mt", "mm", "mb", "md"), ) - def test_anchor(self, anchor, left, left_old, top): + def test_anchor(self, anchor, left, top): name, text = "quick", "Quick" path = f"Tests/images/test_anchor_{name}_{anchor}.png" - freetype = parse_version(features.version_module("freetype2")) - if freetype < parse_version("2.4"): - width, height = (129, 44) - left = left_old - elif self.LAYOUT_ENGINE == ImageFont.LAYOUT_RAQM: + if self.LAYOUT_ENGINE == ImageFont.LAYOUT_RAQM: width, height = (129, 44) else: width, height = (128, 44) @@ -894,7 +886,6 @@ def test_standard_embedded_color(self): assert_image_similar_tofile(im, "Tests/images/standard_embedded.png", 6.2) - @skip_unless_feature_version("freetype2", "2.5.0") def test_cbdt(self): try: font = ImageFont.truetype( @@ -913,7 +904,6 @@ def test_cbdt(self): assert str(e) in ("unimplemented feature", "unknown file format") pytest.skip("freetype compiled without libpng or CBDT support") - @skip_unless_feature_version("freetype2", "2.5.0") def test_cbdt_mask(self): try: font = ImageFont.truetype( @@ -934,7 +924,6 @@ def test_cbdt_mask(self): assert str(e) in ("unimplemented feature", "unknown file format") pytest.skip("freetype compiled without libpng or CBDT support") - @skip_unless_feature_version("freetype2", "2.5.1") def test_sbix(self): try: font = ImageFont.truetype( @@ -953,7 +942,6 @@ def test_sbix(self): assert str(e) in ("unimplemented feature", "unknown file format") pytest.skip("freetype compiled without libpng or SBIX support") - @skip_unless_feature_version("freetype2", "2.5.1") def test_sbix_mask(self): try: font = ImageFont.truetype( @@ -1008,7 +996,6 @@ class TestImageFont_RaqmLayout(TestImageFont): LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM -@skip_unless_feature_version("freetype2", "2.4", "Different metrics") def test_render_mono_size(): # issue 4177 @@ -1024,18 +1011,6 @@ def test_render_mono_size(): assert_image_equal_tofile(im, "Tests/images/text_mono.gif") -def test_freetype_deprecation(monkeypatch): - # Arrange: mock features.version_module to return fake FreeType version - def fake_version_module(module): - return "2.7" - - monkeypatch.setattr(features, "version_module", fake_version_module) - - # Act / Assert - with pytest.warns(DeprecationWarning): - ImageFont.truetype(FONT_PATH, FONT_SIZE) - - @pytest.mark.parametrize( "test_file", [ diff --git a/Tests/test_imagefontctl.py b/Tests/test_imagefontctl.py index f2a914ff716..ffb70cf1799 100644 --- a/Tests/test_imagefontctl.py +++ b/Tests/test_imagefontctl.py @@ -1,13 +1,8 @@ import pytest -from packaging.version import parse as parse_version -from PIL import Image, ImageDraw, ImageFont, features +from PIL import Image, ImageDraw, ImageFont -from .helper import ( - assert_image_similar_tofile, - skip_unless_feature, - skip_unless_feature_version, -) +from .helper import assert_image_similar_tofile, skip_unless_feature FONT_SIZE = 20 FONT_PATH = "Tests/fonts/DejaVuSans/DejaVuSans.ttf" @@ -252,11 +247,6 @@ def test_getlength_combine(mode, direction, text): pytest.skip("libraqm 0.7 or greater not available") -# FreeType 2.5.1 README: Miscellaneous Changes: -# Improved computation of emulated vertical metrics for TrueType fonts. -@skip_unless_feature_version( - "freetype2", "2.5.1", "FreeType <2.5.1 has incompatible ttb metrics" -) @pytest.mark.parametrize("anchor", ("lt", "mm", "rb", "sm")) def test_anchor_ttb(anchor): text = "f" @@ -315,14 +305,6 @@ def test_anchor_ttb(anchor): "name, text, anchor, dir, epsilon", combine_tests, ids=[r[0] for r in combine_tests] ) def test_combine(name, text, dir, anchor, epsilon): - if ( - parse_version(features.version_module("freetype2")) < parse_version("2.5.1") - and dir == "ttb" - ): - # FreeType 2.5.1 README: Miscellaneous Changes: - # Improved computation of emulated vertical metrics for TrueType fonts. - pytest.skip("FreeType <2.5.1 has incompatible ttb metrics") - path = f"Tests/images/test_combine_{name}.png" f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 48) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 7318da5b7b0..077f78ef53c 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -12,19 +12,6 @@ Deprecated features Below are features which are considered deprecated. Where appropriate, a ``DeprecationWarning`` is issued. -FreeType 2.7 -~~~~~~~~~~~~ - -.. deprecated:: 8.1.0 - -Support for FreeType 2.7 is deprecated and will be removed in Pillow 9.0.0 (2022-01-02), -when FreeType 2.8 will be the minimum supported. - -We recommend upgrading to at least FreeType `2.10.4`_, which fixed a severe -vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`). - -.. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/ - Tk/Tcl 8.4 ~~~~~~~~~~ @@ -111,6 +98,19 @@ ImageFile.raise_ioerror So, ``ImageFile.raise_ioerror`` has been removed. Use ``ImageFile.raise_oserror`` instead. +FreeType 2.7 +~~~~~~~~~~~~ + +.. deprecated:: 8.1.0 +.. versionremoved:: 9.0.0 + +Support for FreeType 2.7 has been removed. + +We recommend upgrading to at least `FreeType`_ 2.10.4, which fixed a severe +vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`). + +.. _FreeType: https://www.freetype.org + im.offset ~~~~~~~~~ diff --git a/docs/releasenotes/9.0.0.rst b/docs/releasenotes/9.0.0.rst index 9991655e7b3..6965b65bf8a 100644 --- a/docs/releasenotes/9.0.0.rst +++ b/docs/releasenotes/9.0.0.rst @@ -9,25 +9,44 @@ PILLOW_VERSION constant ``PILLOW_VERSION`` has been removed. Use ``__version__`` instead. +FreeType 2.7 +^^^^^^^^^^^^ + +Support for FreeType 2.7 has been removed; FreeType 2.8 is the minimum supported. + +We recommend upgrading to at least `FreeType`_ 2.10.4, which fixed a severe +vulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`). + +.. _FreeType: https://www.freetype.org + Image.show command parameter -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``command`` parameter has been removed. Use a subclass of :py:class:`PIL.ImageShow.Viewer` instead. Image._showxv -~~~~~~~~~~~~~ +^^^^^^^^^^^^^ ``Image._showxv`` has been removed. Use :py:meth:`~PIL.Image.Image.show` instead. If custom behaviour is required, use :py:meth:`~PIL.ImageShow.register` to add a custom :py:class:`~PIL.ImageShow.Viewer` class. ImageFile.raise_ioerror -~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^ ``IOError`` was merged into ``OSError`` in Python 3.3. So, ``ImageFile.raise_ioerror`` has been removed. Use ``ImageFile.raise_oserror`` instead. + +Deprecations +============ + +TODO +^^^^ + +TODO + API Changes =========== diff --git a/docs/releasenotes/template.rst b/docs/releasenotes/template.rst index bf381114efa..f7271ae2bf8 100644 --- a/docs/releasenotes/template.rst +++ b/docs/releasenotes/template.rst @@ -34,6 +34,9 @@ TODO Security ======== +TODO +^^^^ + TODO Other Changes diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index e99ca21b2a6..a212110a88c 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -28,10 +28,9 @@ import base64 import os import sys -import warnings from io import BytesIO -from . import Image, features +from . import Image from ._util import isDirectory, isPath LAYOUT_BASIC = 0 @@ -165,23 +164,6 @@ def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None) self.index = index self.encoding = encoding - try: - from packaging.version import parse as parse_version - except ImportError: - pass - else: - freetype_version = features.version_module("freetype2") - if freetype_version is not None and parse_version( - freetype_version - ) < parse_version("2.8"): - warnings.warn( - "Support for FreeType 2.7 is deprecated and will be removed" - " in Pillow 9 (2022-01-02). Please upgrade to FreeType 2.8 " - "or newer, preferably FreeType 2.10.4 which fixes " - "CVE-2020-15999.", - DeprecationWarning, - ) - if layout_engine not in (LAYOUT_BASIC, LAYOUT_RAQM): layout_engine = LAYOUT_BASIC if core.HAVE_RAQM: diff --git a/src/_imagingft.c b/src/_imagingft.c index bbfca187eb7..8f19b763c5c 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -933,11 +933,7 @@ font_render(FontObject *self, PyObject *args) { case FT_PIXEL_MODE_GRAY2: case FT_PIXEL_MODE_GRAY4: if (!bitmap_converted_ready) { -#if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR > 6) FT_Bitmap_Init(&bitmap_converted); -#else - FT_Bitmap_New(&bitmap_converted); -#endif bitmap_converted_ready = 1; } error = FT_Bitmap_Convert(library, &bitmap, &bitmap_converted, 1);