mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 01:46:18 +03:00
Merge pull request #6381 from nulano/deprecate-getsize
Deprecate ImageFont.getsize and related functions
This commit is contained in:
commit
488589b4b6
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
@ -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")
|
||||
|
|
|
@ -76,12 +76,19 @@ 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
|
||||
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.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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -1232,21 +1232,39 @@ def test_textsize_empty_string():
|
|||
# Act
|
||||
# Should not cause 'SystemError: <built-in method getsize of
|
||||
# ImagingFont object at 0x...> 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")
|
||||
def test_textsize_stroke():
|
||||
def test_textbbox_stroke():
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
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")
|
||||
|
|
|
@ -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: <built-in method getsize of
|
||||
# ImagingFont object at 0x...> 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")
|
||||
|
|
|
@ -94,7 +94,7 @@ class TestImageFont:
|
|||
def _render(self, font):
|
||||
txt = "Hello World!"
|
||||
ttf = ImageFont.truetype(font, FONT_SIZE, layout_engine=self.LAYOUT_ENGINE)
|
||||
ttf.getsize(txt)
|
||||
ttf.getbbox(txt)
|
||||
|
||||
img = Image.new("RGB", (256, 64), "white")
|
||||
d = ImageDraw.Draw(img)
|
||||
|
@ -135,15 +135,15 @@ class TestImageFont:
|
|||
target = "Tests/images/transparent_background_text_L.png"
|
||||
assert_image_similar_tofile(im.convert("L"), target, 0.01)
|
||||
|
||||
def test_textsize_equal(self):
|
||||
def test_textbbox_equal(self):
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
ttf = self.get_font()
|
||||
|
||||
txt = "Hello World!"
|
||||
size = draw.textsize(txt, ttf)
|
||||
bbox = draw.textbbox((10, 10), txt, ttf)
|
||||
draw.text((10, 10), txt, font=ttf)
|
||||
draw.rectangle((10, 10, 10 + size[0], 10 + size[1]))
|
||||
draw.rectangle(bbox)
|
||||
|
||||
assert_image_similar_tofile(
|
||||
im, "Tests/images/rectangle_surrounding_text.png", 2.5
|
||||
|
@ -184,7 +184,7 @@ class TestImageFont:
|
|||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
ttf = self.get_font()
|
||||
line_spacing = draw.textsize("A", font=ttf)[1] + 4
|
||||
line_spacing = ttf.getbbox("A")[3] + 4
|
||||
lines = TEST_TEXT.split("\n")
|
||||
y = 0
|
||||
for line in lines:
|
||||
|
@ -245,19 +245,39 @@ class TestImageFont:
|
|||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
|
||||
# Test that textsize() correctly connects to multiline_textsize()
|
||||
assert draw.textsize(TEST_TEXT, font=ttf) == draw.multiline_textsize(
|
||||
TEST_TEXT, font=ttf
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
# Test that textsize() correctly connects to multiline_textsize()
|
||||
assert draw.textsize(TEST_TEXT, font=ttf) == draw.multiline_textsize(
|
||||
TEST_TEXT, font=ttf
|
||||
)
|
||||
|
||||
# Test that multiline_textsize corresponds to ImageFont.textsize()
|
||||
# for single line text
|
||||
assert ttf.getsize("A") == draw.multiline_textsize("A", font=ttf)
|
||||
|
||||
# Test that textsize() can pass on additional arguments
|
||||
# to multiline_textsize()
|
||||
draw.textsize(TEST_TEXT, font=ttf, spacing=4)
|
||||
draw.textsize(TEST_TEXT, ttf, 4)
|
||||
assert len(log) == 6
|
||||
|
||||
def test_multiline_bbox(self):
|
||||
ttf = self.get_font()
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
|
||||
# Test that textbbox() correctly connects to multiline_textbbox()
|
||||
assert draw.textbbox((0, 0), TEST_TEXT, font=ttf) == draw.multiline_textbbox(
|
||||
(0, 0), TEST_TEXT, font=ttf
|
||||
)
|
||||
|
||||
# Test that multiline_textsize corresponds to ImageFont.textsize()
|
||||
# Test that multiline_textbbox corresponds to ImageFont.textbbox()
|
||||
# for single line text
|
||||
assert ttf.getsize("A") == draw.multiline_textsize("A", font=ttf)
|
||||
assert ttf.getbbox("A") == draw.multiline_textbbox((0, 0), "A", font=ttf)
|
||||
|
||||
# Test that textsize() can pass on additional arguments
|
||||
# to multiline_textsize()
|
||||
draw.textsize(TEST_TEXT, font=ttf, spacing=4)
|
||||
draw.textsize(TEST_TEXT, ttf, 4)
|
||||
# Test that textbbox() can pass on additional arguments
|
||||
# to multiline_textbbox()
|
||||
draw.textbbox((0, 0), TEST_TEXT, font=ttf, spacing=4)
|
||||
|
||||
def test_multiline_width(self):
|
||||
ttf = self.get_font()
|
||||
|
@ -265,9 +285,15 @@ class TestImageFont:
|
|||
draw = ImageDraw.Draw(im)
|
||||
|
||||
assert (
|
||||
draw.textsize("longest line", font=ttf)[0]
|
||||
== draw.multiline_textsize("longest line\nline", font=ttf)[0]
|
||||
draw.textbbox((0, 0), "longest line", font=ttf)[2]
|
||||
== draw.multiline_textbbox((0, 0), "longest line\nline", font=ttf)[2]
|
||||
)
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
assert (
|
||||
draw.textsize("longest line", font=ttf)[0]
|
||||
== draw.multiline_textsize("longest line\nline", font=ttf)[0]
|
||||
)
|
||||
assert len(log) == 2
|
||||
|
||||
def test_multiline_spacing(self):
|
||||
ttf = self.get_font()
|
||||
|
@ -289,16 +315,33 @@ class TestImageFont:
|
|||
|
||||
# Original font
|
||||
draw.font = font
|
||||
box_size_a = draw.textsize(word)
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
box_size_a = draw.textsize(word)
|
||||
assert box_size_a == font.getsize(word)
|
||||
assert len(log) == 2
|
||||
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 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
|
||||
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)
|
||||
|
@ -310,15 +353,31 @@ class TestImageFont:
|
|||
|
||||
# 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"
|
||||
|
@ -373,9 +432,11 @@ class TestImageFont:
|
|||
text = "offset this"
|
||||
|
||||
# Act
|
||||
offset = font.getoffset(text)
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
offset = font.getoffset(text)
|
||||
|
||||
# Assert
|
||||
assert len(log) == 1
|
||||
assert offset == (0, 3)
|
||||
|
||||
def test_free_type_font_get_mask(self):
|
||||
|
@ -417,11 +478,11 @@ class TestImageFont:
|
|||
# Assert
|
||||
assert_image_equal_tofile(im, "Tests/images/default_font.png")
|
||||
|
||||
def test_getsize_empty(self):
|
||||
def test_getbbox_empty(self):
|
||||
# issue #2614
|
||||
font = self.get_font()
|
||||
# should not crash.
|
||||
assert (0, 0) == font.getsize("")
|
||||
assert (0, 0, 0, 0) == font.getbbox("")
|
||||
|
||||
def test_render_empty(self):
|
||||
# issue 2666
|
||||
|
@ -438,7 +499,7 @@ class TestImageFont:
|
|||
# issue #2826
|
||||
font = ImageFont.load_default()
|
||||
with pytest.raises(UnicodeEncodeError):
|
||||
font.getsize("’")
|
||||
font.getbbox("’")
|
||||
|
||||
def test_unicode_extended(self):
|
||||
# issue #3777
|
||||
|
@ -563,17 +624,29 @@ class TestImageFont:
|
|||
assert t.font.x_ppem == 20
|
||||
assert t.font.y_ppem == 20
|
||||
assert t.font.glyphs == 4177
|
||||
assert t.getsize("A") == (12, 16)
|
||||
assert t.getsize("AB") == (24, 16)
|
||||
assert t.getsize("M") == (12, 16)
|
||||
assert t.getsize("y") == (12, 20)
|
||||
assert t.getsize("a") == (12, 16)
|
||||
assert t.getsize_multiline("A") == (12, 16)
|
||||
assert t.getsize_multiline("AB") == (24, 16)
|
||||
assert t.getsize_multiline("a") == (12, 16)
|
||||
assert t.getsize_multiline("ABC\n") == (36, 36)
|
||||
assert t.getsize_multiline("ABC\nA") == (36, 36)
|
||||
assert t.getsize_multiline("ABC\nAaaa") == (48, 36)
|
||||
assert t.getbbox("A") == (0, 4, 12, 16)
|
||||
assert t.getbbox("AB") == (0, 4, 24, 16)
|
||||
assert t.getbbox("M") == (0, 4, 12, 16)
|
||||
assert t.getbbox("y") == (0, 7, 12, 20)
|
||||
assert t.getbbox("a") == (0, 7, 12, 16)
|
||||
assert t.getlength("A") == 12
|
||||
assert t.getlength("AB") == 24
|
||||
assert t.getlength("M") == 12
|
||||
assert t.getlength("y") == 12
|
||||
assert t.getlength("a") == 12
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
assert t.getsize("A") == (12, 16)
|
||||
assert t.getsize("AB") == (24, 16)
|
||||
assert t.getsize("M") == (12, 16)
|
||||
assert t.getsize("y") == (12, 20)
|
||||
assert t.getsize("a") == (12, 16)
|
||||
assert t.getsize_multiline("A") == (12, 16)
|
||||
assert t.getsize_multiline("AB") == (24, 16)
|
||||
assert t.getsize_multiline("a") == (12, 16)
|
||||
assert t.getsize_multiline("ABC\n") == (36, 36)
|
||||
assert t.getsize_multiline("ABC\nA") == (36, 36)
|
||||
assert t.getsize_multiline("ABC\nAaaa") == (48, 36)
|
||||
assert len(log) == 11
|
||||
|
||||
def test_getsize_stroke(self):
|
||||
# Arrange
|
||||
|
@ -581,14 +654,22 @@ class TestImageFont:
|
|||
|
||||
# Act / Assert
|
||||
for stroke_width in [0, 2]:
|
||||
assert t.getsize("A", stroke_width=stroke_width) == (
|
||||
12 + stroke_width * 2,
|
||||
16 + stroke_width * 2,
|
||||
)
|
||||
assert t.getsize_multiline("ABC\nAaaa", stroke_width=stroke_width) == (
|
||||
48 + stroke_width * 2,
|
||||
36 + stroke_width * 4,
|
||||
assert t.getbbox("A", stroke_width=stroke_width) == (
|
||||
0 - stroke_width,
|
||||
4 - stroke_width,
|
||||
12 + stroke_width,
|
||||
16 + stroke_width,
|
||||
)
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
assert t.getsize("A", stroke_width=stroke_width) == (
|
||||
12 + stroke_width * 2,
|
||||
16 + stroke_width * 2,
|
||||
)
|
||||
assert t.getsize_multiline("ABC\nAaaa", stroke_width=stroke_width) == (
|
||||
48 + stroke_width * 2,
|
||||
36 + stroke_width * 4,
|
||||
)
|
||||
assert len(log) == 2
|
||||
|
||||
def test_complex_font_settings(self):
|
||||
# Arrange
|
||||
|
@ -720,8 +801,11 @@ class TestImageFont:
|
|||
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",
|
||||
|
@ -868,7 +952,7 @@ class TestImageFont:
|
|||
def test_standard_embedded_color(self):
|
||||
txt = "Hello World!"
|
||||
ttf = ImageFont.truetype(FONT_PATH, 40, layout_engine=self.LAYOUT_ENGINE)
|
||||
ttf.getsize(txt)
|
||||
ttf.getbbox(txt)
|
||||
|
||||
im = Image.new("RGB", (300, 64), "white")
|
||||
d = ImageDraw.Draw(im)
|
||||
|
|
|
@ -140,8 +140,8 @@ def test_ligature_features():
|
|||
target = "Tests/images/test_ligature_features.png"
|
||||
assert_image_similar_tofile(im, target, 0.5)
|
||||
|
||||
liga_size = ttf.getsize("fi", features=["-liga"])
|
||||
assert liga_size == (13, 19)
|
||||
liga_bbox = ttf.getbbox("fi", features=["-liga"])
|
||||
assert liga_bbox == (0, 4, 13, 19)
|
||||
|
||||
|
||||
def test_kerning_features():
|
||||
|
|
|
@ -178,6 +178,25 @@ 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
|
||||
|
||||
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
|
||||
=========================================================================== =============================================================================================================
|
||||
: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`
|
||||
:py:meth:`.ImageDraw2.Draw.textsize` :py:meth:`.ImageDraw2.Draw.textbbox` and :py:meth:`.ImageDraw2.Draw.textlength`
|
||||
=========================================================================== =============================================================================================================
|
||||
|
||||
Removed features
|
||||
----------------
|
||||
|
||||
|
|
|
@ -436,12 +436,14 @@ Methods
|
|||
|
||||
.. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
|
||||
|
||||
Return the size of the given string, in pixels.
|
||||
.. 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.
|
||||
|
||||
.. 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
|
||||
|
@ -484,6 +486,10 @@ 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.
|
||||
|
||||
Use :py:meth:`textlength()` to measure the offset of following text with
|
||||
|
|
|
@ -56,6 +56,7 @@ Methods
|
|||
|
||||
.. autoclass:: PIL.ImageFont.TransposedFont
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
|
|
@ -40,6 +40,25 @@ 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
|
||||
|
||||
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
|
||||
=========================================================================== =============================================================================================================
|
||||
: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`
|
||||
:py:meth:`.ImageDraw2.Draw.textsize` :py:meth:`.ImageDraw2.Draw.textbbox` and :py:meth:`.ImageDraw2.Draw.textlength`
|
||||
=========================================================================== =============================================================================================================
|
||||
|
||||
API Additions
|
||||
=============
|
||||
|
||||
|
|
|
@ -32,8 +32,10 @@
|
|||
|
||||
import math
|
||||
import numbers
|
||||
import warnings
|
||||
|
||||
from . import Image, ImageColor
|
||||
from ._deprecate import deprecate
|
||||
|
||||
"""
|
||||
A simple 2D drawing interface for PIL images.
|
||||
|
@ -372,6 +374,19 @@ class ImageDraw:
|
|||
|
||||
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
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
return (
|
||||
self.textsize(
|
||||
"A",
|
||||
font=font,
|
||||
stroke_width=stroke_width,
|
||||
)[1]
|
||||
+ spacing
|
||||
)
|
||||
|
||||
def text(
|
||||
self,
|
||||
xy,
|
||||
|
@ -511,9 +526,7 @@ class ImageDraw:
|
|||
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
|
||||
|
@ -573,14 +586,31 @@ class ImageDraw:
|
|||
stroke_width=0,
|
||||
):
|
||||
"""Get the size of a given string, in pixels."""
|
||||
deprecate("textsize", 10, "textbbox or textlength")
|
||||
if self._multiline_check(text):
|
||||
return self.multiline_textsize(
|
||||
text, font, spacing, direction, features, language, stroke_width
|
||||
)
|
||||
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()
|
||||
return font.getsize(text, direction, features, language, stroke_width)
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
return font.getsize(
|
||||
text,
|
||||
direction,
|
||||
features,
|
||||
language,
|
||||
stroke_width,
|
||||
)
|
||||
|
||||
def multiline_textsize(
|
||||
self,
|
||||
|
@ -592,16 +622,23 @@ class ImageDraw:
|
|||
language=None,
|
||||
stroke_width=0,
|
||||
):
|
||||
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
|
||||
)
|
||||
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)
|
||||
line_spacing = self._multiline_spacing(font, spacing, stroke_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(
|
||||
|
@ -625,9 +662,16 @@ class ImageDraw:
|
|||
try:
|
||||
return font.getlength(text, mode, direction, features, language)
|
||||
except AttributeError:
|
||||
size = self.textsize(
|
||||
text, font, direction=direction, features=features, language=language
|
||||
)
|
||||
deprecate("textlength support for fonts without getlength", 10)
|
||||
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]
|
||||
|
@ -667,10 +711,6 @@ class ImageDraw:
|
|||
|
||||
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
|
||||
|
@ -704,9 +744,7 @@ class ImageDraw:
|
|||
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,
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
"""
|
||||
|
||||
|
||||
import warnings
|
||||
|
||||
from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
|
||||
from ._deprecate import deprecate
|
||||
|
||||
|
||||
class Pen:
|
||||
|
@ -172,8 +175,35 @@ class Draw:
|
|||
|
||||
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`
|
||||
"""
|
||||
return self.draw.textsize(text, font=font.font)
|
||||
deprecate("textsize", 10, "textbbox or textlength")
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
return self.draw.textsize(text, font=font.font)
|
||||
|
||||
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)
|
||||
|
|
|
@ -137,12 +137,17 @@ class ImageFont:
|
|||
|
||||
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.
|
||||
|
||||
: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):
|
||||
|
@ -165,6 +170,33 @@ class ImageFont:
|
|||
"""
|
||||
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
|
||||
|
@ -386,16 +418,23 @@ class FreeTypeFont:
|
|||
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,
|
||||
):
|
||||
"""
|
||||
Returns width and height (in pixels) of given text if rendered in font with
|
||||
provided direction, features, and language.
|
||||
.. 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.
|
||||
|
||||
.. 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
|
||||
|
@ -438,6 +477,7 @@ class FreeTypeFont:
|
|||
|
||||
: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)
|
||||
|
@ -456,6 +496,10 @@ class FreeTypeFont:
|
|||
stroke_width=0,
|
||||
):
|
||||
"""
|
||||
.. 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
|
||||
newline characters.
|
||||
|
@ -495,19 +539,26 @@ class FreeTypeFont:
|
|||
|
||||
:return: (width, height)
|
||||
"""
|
||||
deprecate("getsize_multiline", 10, "ImageDraw.multiline_textbbox")
|
||||
max_width = 0
|
||||
lines = self._multiline_split(text)
|
||||
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)
|
||||
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.
|
||||
|
||||
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`.
|
||||
|
@ -516,6 +567,7 @@ class FreeTypeFont:
|
|||
|
||||
:return: A tuple of the x and y offset
|
||||
"""
|
||||
deprecate("getoffset", 10, "getbbox")
|
||||
return self.font.getsize(text)[1]
|
||||
|
||||
def getmask(
|
||||
|
@ -796,7 +848,15 @@ class TransposedFont:
|
|||
self.orientation = orientation # any 'transpose' argument, or None
|
||||
|
||||
def getsize(self, text, *args, **kwargs):
|
||||
w, h = self.font.getsize(text)
|
||||
"""
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead.
|
||||
"""
|
||||
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
|
||||
|
@ -807,6 +867,23 @@ class TransposedFont:
|
|||
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 text rotated by 90 or 270 degrees"
|
||||
)
|
||||
return self.font.getlength(text, *args, **kwargs)
|
||||
|
||||
|
||||
def load(filename):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue
Block a user