diff --git a/Tests/fonts/GreatVibes-Regular.ttf b/Tests/fonts/GreatVibes-Regular.ttf new file mode 100644 index 00000000000..acc5d37f7a5 Binary files /dev/null and b/Tests/fonts/GreatVibes-Regular.ttf differ diff --git a/Tests/fonts/LICENSE.txt b/Tests/fonts/LICENSE.txt index 94989af9035..71bbc075946 100644 --- a/Tests/fonts/LICENSE.txt +++ b/Tests/fonts/LICENSE.txt @@ -8,6 +8,7 @@ ArefRuqaa-Regular.ttf, from https://github.com/google/fonts/tree/master/ofl/aref ter-x20b.pcf, from http://terminus-font.sourceforge.net/ BungeeColor-Regular_colr_Windows.ttf, from https://github.com/djrrb/bungee OpenSans.woff2, from https://fonts.googleapis.com/css?family=Open+Sans +GreatVibes-Regular.ttf, from https://fonts.google.com/specimen/Great+Vibes All of the above fonts are published under the SIL Open Font License (OFL) v1.1 (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL), which allows you to copy, modify, and redistribute them if you need to. diff --git a/Tests/images/use_max_line_height.png b/Tests/images/use_max_line_height.png new file mode 100644 index 00000000000..ca8528ba808 Binary files /dev/null and b/Tests/images/use_max_line_height.png differ diff --git a/Tests/test_imagetext.py b/Tests/test_imagetext.py index 507d8240918..fe2c73b954e 100644 --- a/Tests/test_imagetext.py +++ b/Tests/test_imagetext.py @@ -1,10 +1,16 @@ from __future__ import annotations +import sysconfig + import pytest from PIL import Image, ImageDraw, ImageFont, ImageText, features -from .helper import assert_image_similar_tofile, skip_unless_feature +from .helper import ( + assert_image_equal_tofile, + assert_image_similar_tofile, + skip_unless_feature, +) FONT_PATH = "Tests/fonts/FreeMono.ttf" @@ -71,6 +77,21 @@ def test_get_bbox( assert ImageText.Text(text, font).get_bbox() == expected +def test_use_max_line_height() -> None: + font = ImageFont.truetype("Tests/fonts/GreatVibes-Regular.ttf", 120) + text = ImageText.Text("adjust\nYellow", font) + text.use_max_line_height() + + im = Image.new("RGB", (309, 306)) + draw = ImageDraw.Draw(im) + draw.text((0, 0), text, "#ff0") + expected = "Tests/images/use_max_line_height.png" + if sysconfig.get_platform() in ("win32", "win-amd64"): + assert_image_similar_tofile(im, expected, 12.28) + else: + assert_image_equal_tofile(im, expected) + + def test_standard_embedded_color(layout_engine: ImageFont.Layout) -> None: if features.check_module("freetype2"): font = ImageFont.truetype(FONT_PATH, 40, layout_engine=layout_engine) diff --git a/src/PIL/ImageText.py b/src/PIL/ImageText.py index 008d20d38e1..b85f801dc95 100644 --- a/src/PIL/ImageText.py +++ b/src/PIL/ImageText.py @@ -141,10 +141,24 @@ def __init__( self.language = language self.embedded_color = False + self.line_height: float | None = None self.stroke_width: float = 0 self.stroke_fill: _Ink | None = None + def use_max_line_height(self) -> None: + """ + Use the maximum line height from the text. + """ + self.line_height = self.font.getbbox( + self.text, + self._get_fontmode(), + None, + self.features, + self.language, + self.stroke_width, + )[3] + def embed_color(self) -> None: """ Use embedded color glyphs (COLR, CBDT, SBIX). @@ -351,8 +365,10 @@ def _split( raise ValueError(msg) fontmode = self._get_fontmode() - line_spacing = ( - self.font.getbbox( + if self.line_height is not None: + line_height = self.line_height + else: + line_height = self.font.getbbox( "A", fontmode, None, @@ -360,9 +376,7 @@ def _split( self.language, self.stroke_width, )[3] - + self.stroke_width - + self.spacing - ) + line_spacing = line_height + self.stroke_width + self.spacing top = xy[1] parts = []