Skip to content

Commit d27ce5f

Browse files
committed
Added scaling argument to wrap()
1 parent e5fc2d3 commit d27ce5f

File tree

3 files changed

+263
-144
lines changed

3 files changed

+263
-144
lines changed

Tests/test_imagetext.py

Lines changed: 104 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import pytest
44

5-
from PIL import Image, ImageDraw, ImageFont, ImageText
5+
from PIL import Image, ImageDraw, ImageFont, ImageText, features
66

77
from .helper import assert_image_similar_tofile, skip_unless_feature
88

@@ -84,27 +84,120 @@ def test_stroke() -> None:
8484

8585

8686
@pytest.mark.parametrize(
87-
"text, width, expected",
87+
"data, width, expected",
8888
(
8989
("Hello World!", 100, "Hello World!"), # No wrap required
9090
("Hello World!", 50, "Hello\nWorld!"), # Wrap word to a new line
91-
("Hello World!", 25, "Hello\nWorl\nd!"), # Split word across lines
9291
# Keep multiple spaces within a line
93-
("Keep multiple spaces", 75, "Keep multiple\nspaces"),
92+
("Keep multiple spaces", 90, "Keep multiple\nspaces"),
93+
(" Keep\n leading space", 100, " Keep\n leading space"),
9494
),
9595
)
9696
@pytest.mark.parametrize("string", (True, False))
97-
def test_wrap(text: str, width: int, expected: str, string: bool) -> None:
98-
text = ImageText.Text(text if string else text.encode())
99-
assert text.wrap(width) is None
100-
assert text.text == expected if string else expected.encode()
97+
def test_wrap(data: str, width: int, expected: str, string: bool) -> None:
98+
if string:
99+
text = ImageText.Text(data)
100+
assert text.wrap(width) is None
101+
assert text.text == expected
102+
else:
103+
text_bytes = ImageText.Text(data.encode())
104+
assert text_bytes.wrap(width) is None
105+
assert text_bytes.text == expected.encode()
106+
107+
108+
def test_wrap_long_word() -> None:
109+
text = ImageText.Text("Hello World!")
110+
with pytest.raises(ValueError, match="Word does not fit within line"):
111+
text.wrap(25)
112+
113+
114+
def test_wrap_unsupported(font: ImageFont.FreeTypeFont) -> None:
115+
transposed_font = ImageFont.TransposedFont(font)
116+
text = ImageText.Text("Hello World!", transposed_font)
117+
with pytest.raises(ValueError, match="TransposedFont not supported"):
118+
text.wrap(50)
119+
120+
text = ImageText.Text("Hello World!", direction="ttb")
121+
with pytest.raises(ValueError, match="Only ltr direction supported"):
122+
text.wrap(50)
101123

102124

103125
def test_wrap_height() -> None:
126+
width = 50 if features.check_module("freetype2") else 60
104127
text = ImageText.Text("Text does not fit within height")
105-
assert text.wrap(50, 25).text == " within height"
128+
wrapped = text.wrap(width, 25 if features.check_module("freetype2") else 40)
129+
assert wrapped is not None
130+
assert wrapped.text == " within height"
106131
assert text.text == "Text does\nnot fit"
107132

108-
text = ImageText.Text("Text does not fit singlelongword")
109-
assert text.wrap(50, 25).text == " singlelongword"
133+
text = ImageText.Text("Text does not fit\nwithin height")
134+
wrapped = text.wrap(width, 20)
135+
assert wrapped is not None
136+
assert wrapped.text == " not fit\nwithin height"
137+
assert text.text == "Text does"
138+
139+
text = ImageText.Text("Text does not fit\n\nwithin height")
140+
wrapped = text.wrap(width, 25 if features.check_module("freetype2") else 40)
141+
assert wrapped is not None
142+
assert wrapped.text == "\nwithin height"
110143
assert text.text == "Text does\nnot fit"
144+
145+
146+
def test_wrap_scaling_unsupported() -> None:
147+
font = ImageFont.load_default_imagefont()
148+
text = ImageText.Text("Hello World!", font)
149+
with pytest.raises(ValueError, match="'scaling' only supports FreeTypeFont"):
150+
text.wrap(50, scaling="shrink")
151+
152+
if features.check_module("freetype2"):
153+
text = ImageText.Text("Hello World!")
154+
with pytest.raises(ValueError, match="'scaling' requires 'height'"):
155+
text.wrap(50, scaling="shrink")
156+
157+
158+
@skip_unless_feature("freetype2")
159+
def test_wrap_shrink() -> None:
160+
# No scaling required
161+
text = ImageText.Text("Hello World!")
162+
assert isinstance(text.font, ImageFont.FreeTypeFont)
163+
assert text.font.size == 10
164+
assert text.wrap(50, 50, "shrink") is None
165+
assert isinstance(text.font, ImageFont.FreeTypeFont)
166+
assert text.font.size == 10
167+
168+
with pytest.raises(ValueError, match="Text could not be scaled"):
169+
text.wrap(50, 15, ("shrink", 9))
170+
171+
assert text.wrap(50, 15, "shrink") is None
172+
assert text.font.size == 8
173+
174+
text = ImageText.Text("Hello World!")
175+
assert text.wrap(50, 15, ("shrink", 7)) is None
176+
assert isinstance(text.font, ImageFont.FreeTypeFont)
177+
assert text.font.size == 8
178+
179+
180+
@skip_unless_feature("freetype2")
181+
def test_wrap_grow() -> None:
182+
# No scaling required
183+
text = ImageText.Text("Hello World!")
184+
assert isinstance(text.font, ImageFont.FreeTypeFont)
185+
assert text.font.size == 10
186+
assert text.wrap(58, 10, "grow") is None
187+
assert isinstance(text.font, ImageFont.FreeTypeFont)
188+
assert text.font.size == 10
189+
190+
with pytest.raises(ValueError, match="Text could not be scaled"):
191+
text.wrap(50, 50, ("grow", 12))
192+
193+
assert text.wrap(50, 50, "grow") is None
194+
assert text.font.size == 16
195+
196+
text = ImageText.Text("A\nB")
197+
with pytest.raises(ValueError, match="Text could not be scaled"):
198+
text.wrap(50, 10, "grow")
199+
200+
text = ImageText.Text("Hello World!")
201+
assert text.wrap(50, 50, ("grow", 18)) is None
202+
assert isinstance(text.font, ImageFont.FreeTypeFont)
203+
assert text.font.size == 16

src/PIL/ImageDraw.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ def draw_corners(pieslice: bool) -> None:
538538
def text(
539539
self,
540540
xy: tuple[float, float],
541-
text: AnyStr | ImageText.Text,
541+
text: AnyStr | ImageText.Text[AnyStr],
542542
fill: _Ink | None = None,
543543
font: (
544544
ImageFont.ImageFont

0 commit comments

Comments
 (0)