fix and add tests

This commit is contained in:
nulano 2020-04-22 03:02:08 +02:00
parent 396c8c9486
commit 6e3276ab31
58 changed files with 142 additions and 19 deletions

View File

@ -1,5 +1,6 @@
NotoNastaliqUrdu-Regular.ttf and NotoSansSymbols-Regular.ttf, from https://github.com/googlei18n/noto-fonts
NotoSans-Regular.ttf, from https://www.google.com/get/noto/
NotoSansJP-Thin.otf, from https://www.google.com/get/noto/help/cjk/
AdobeVFPrototype.ttf, from https://github.com/adobe-fonts/adobe-variable-font-prototype
TINY5x3GX.ttf, from http://velvetyne.fr/fonts/tiny

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 963 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 777 B

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 605 B

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 810 B

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -5,7 +5,7 @@ from .helper import PillowLeakTestCase, skip_unless_feature
class TestTTypeFontLeak(PillowLeakTestCase):
# fails at iteration 3 in master
iterations = 10
iterations = 40
mem_limit = 4096 # k
def _test_font(self, font):
@ -13,7 +13,7 @@ class TestTTypeFontLeak(PillowLeakTestCase):
draw = ImageDraw.ImageDraw(im)
self._test_leak(
lambda: draw.text(
(0, 0), "some text " * 1024, font=font, fill="black" # ~10k
(0, 0), "some text " * 256, font=font, fill="black" # ~10k
)
)
@ -25,7 +25,7 @@ class TestTTypeFontLeak(PillowLeakTestCase):
class TestDefaultFontLeak(TestTTypeFontLeak):
# fails at iteration 37 in master
iterations = 100
iterations = 400
mem_limit = 1024 # k
def test_leak(self):

View File

@ -1015,7 +1015,7 @@ def test_stroke():
font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120)
# Act
draw.text((10, 10), "A", "#f00", font, stroke_width=2, stroke_fill=stroke_fill)
draw.text((12, 12), "A", "#f00", font, stroke_width=2, stroke_fill=stroke_fill)
# Assert
assert_image_similar(
@ -1031,11 +1031,11 @@ def test_stroke_descender():
font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120)
# Act
draw.text((10, 0), "y", "#f00", font, stroke_width=2, stroke_fill="#0f0")
draw.text((12, 2), "y", "#f00", font, stroke_width=2, stroke_fill="#0f0")
# Assert
assert_image_similar(
im, Image.open("Tests/images/imagedraw_stroke_descender.png"), 6.76
im, Image.open("Tests/images/imagedraw_stroke_descender.png"), 6.78
)
@ -1048,7 +1048,7 @@ def test_stroke_multiline():
# Act
draw.multiline_text(
(10, 10), "A\nB", "#f00", font, stroke_width=2, stroke_fill="#0f0"
(12, 12), "A\nB", "#f00", font, stroke_width=2, stroke_fill="#0f0"
)
# Assert

View File

@ -34,7 +34,7 @@ class TestImageFont:
# Freetype has different metrics depending on the version.
# (and, other things, but first things first)
METRICS = {
(">=2.3", "<2.4"): {"multiline": 30, "textsize": 12, "getters": (13, 16)},
(">=2.3", "<2.4"): {"multiline": 30, "textsize": 12, "getters": (12, 16)},
(">=2.7",): {"multiline": 6.2, "textsize": 2.5, "getters": (12, 16)},
"Default": {"multiline": 0.5, "textsize": 0.5, "getters": (12, 16)},
}
@ -342,7 +342,7 @@ class TestImageFont:
mask = transposed_font.getmask(text)
# Assert
assert mask.size == (13, 108)
assert mask.size in ((13, 107), (13, 108))
def test_unrotated_transposed_font_get_mask(self):
# Arrange
@ -355,7 +355,7 @@ class TestImageFont:
mask = transposed_font.getmask(text)
# Assert
assert mask.size == (108, 13)
assert mask.size in ((107, 13), (108, 13))
def test_free_type_font_get_name(self):
# Arrange
@ -399,7 +399,7 @@ class TestImageFont:
mask = font.getmask(text)
# Assert
assert mask.size == (108, 13)
assert mask.size in ((107, 13), (108, 13))
def test_load_path_not_found(self):
# Arrange
@ -470,7 +470,8 @@ class TestImageFont:
d = ImageDraw.Draw(img)
d.text((10, 10), text, font=ttf)
assert_image_similar_tofile(img, target, self.metrics["multiline"])
# fails with 14.7
assert_image_similar_tofile(img, target, 6.2)
def _test_fake_loading_font(self, monkeypatch, path_to_fake, fontname):
# Make a copy of FreeTypeFont so we can patch the original
@ -702,10 +703,10 @@ class TestImageFont:
font.set_variation_by_name("Bold")
font = ImageFont.truetype("Tests/fonts/AdobeVFPrototype.ttf", 36)
self._check_text(font, "Tests/images/variation_adobe.png", 11)
self._check_text(font, "Tests/images/variation_adobe.png", 11.2)
for name in ["Bold", b"Bold"]:
font.set_variation_by_name(name)
self._check_text(font, "Tests/images/variation_adobe_name.png", 11)
self._check_text(font, "Tests/images/variation_adobe_name.png", 11.3)
font = ImageFont.truetype("Tests/fonts/TINY5x3GX.ttf", 36)
self._check_text(font, "Tests/images/variation_tiny.png", 40)
@ -727,12 +728,42 @@ class TestImageFont:
font = ImageFont.truetype("Tests/fonts/AdobeVFPrototype.ttf", 36)
font.set_variation_by_axes([500, 50])
self._check_text(font, "Tests/images/variation_adobe_axes.png", 5.1)
self._check_text(font, "Tests/images/variation_adobe_axes.png", 5.8)
font = ImageFont.truetype("Tests/fonts/TINY5x3GX.ttf", 36)
font.set_variation_by_axes([100])
self._check_text(font, "Tests/images/variation_tiny_axes.png", 32.5)
@pytest.mark.parametrize(
"name,text,anchor",
(
# test horizontal anchors
("quick", "Quick", "ls"),
("quick", "Quick", "ms"),
("quick", "Quick", "rs"),
# test vertical anchors
("quick", "Quick", "ma"),
("quick", "Quick", "mt"),
("quick", "Quick", "mm"),
("quick", "Quick", "mb"),
("quick", "Quick", "md"),
),
)
def test_anchor(self, name, text, anchor):
path = "Tests/images/test_anchor_%s_%s.png" % (name, anchor)
f = ImageFont.truetype(
"Tests/fonts/NotoSans-Regular.ttf", 48, layout_engine=self.LAYOUT_ENGINE
)
im = Image.new("RGB", (200, 200), "white")
d = ImageDraw.Draw(im)
d.line(((0, 100), (200, 100)), "gray")
d.line(((100, 0), (100, 200)), "gray")
d.text((100, 100), text, fill="black", anchor=anchor, font=f)
with Image.open(path) as expected:
assert_image_similar(im, expected, 7)
@skip_unless_feature("raqm")
class TestImageFont_RaqmLayout(TestImageFont):

View File

@ -1,3 +1,5 @@
import distutils.version
import pytest
from PIL import Image, ImageDraw, ImageFont
@ -205,3 +207,92 @@ def test_language():
target = "Tests/images/test_language.png"
with Image.open(target) as target_img:
assert_image_similar(im, target_img, 0.5)
@pytest.mark.parametrize("anchor", ("lt", "mm", "rb", "sm"))
def test_anchor_ttb(anchor):
if distutils.version.StrictVersion(ImageFont.core.freetype2_version) < "2.5.1":
# 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")
text = "f"
path = "Tests/images/test_anchor_ttb_%s_%s.png" % (text, anchor)
f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 120)
im = Image.new("RGB", (200, 400), "white")
d = ImageDraw.Draw(im)
d.line(((0, 200), (200, 200)), "gray")
d.line(((100, 0), (100, 400)), "gray")
try:
d.text((100, 200), text, fill="black", anchor=anchor, direction="ttb", font=f)
except ValueError as ex:
if str(ex) == "libraqm 0.7 or greater required for 'ttb' direction":
pytest.skip("libraqm 0.7 or greater not available")
with Image.open(path) as expected:
assert_image_similar(im, expected, 1) # fails at 5
combine_tests = (
# extends above (e.g. issue #4553)
("caron", "a\u030C\u030C\u030C\u030C\u030Cb", None, None, 0.08),
("caron_la", "a\u030C\u030C\u030C\u030C\u030Cb", "la", None, 0.08),
("caron_lt", "a\u030C\u030C\u030C\u030C\u030Cb", "lt", None, 0.08),
("caron_ls", "a\u030C\u030C\u030C\u030C\u030Cb", "ls", None, 0.08),
("caron_ttb", "ca" + ("\u030C" * 15) + "b", None, "ttb", 0.3),
("caron_ttb_lt", "ca" + ("\u030C" * 15) + "b", "lt", "ttb", 0.3),
# extends below
("caron_below", "a\u032C\u032C\u032C\u032C\u032Cb", None, None, 0.02),
("caron_below_ld", "a\u032C\u032C\u032C\u032C\u032Cb", "ld", None, 0.02),
("caron_below_lb", "a\u032C\u032C\u032C\u032C\u032Cb", "lb", None, 0.02),
("caron_below_ls", "a\u032C\u032C\u032C\u032C\u032Cb", "ls", None, 0.02),
("caron_below_ttb", "a" + ("\u032C" * 15) + "b", None, "ttb", 0.03),
("caron_below_ttb_lb", "a" + ("\u032C" * 15) + "b", "lb", "ttb", 0.03),
# extends to the right (e.g. issue #3745)
("double_breve_below", "a\u035Ci", None, None, 0.02),
("double_breve_below_ma", "a\u035Ci", "ma", None, 0.02),
("double_breve_below_ra", "a\u035Ci", "ra", None, 0.02),
("double_breve_below_ttb", "a\u035Cb", None, "ttb", 0.02),
("double_breve_below_ttb_rt", "a\u035Cb", "rt", "ttb", 0.02),
("double_breve_below_ttb_mt", "a\u035Cb", "mt", "ttb", 0.02),
("double_breve_below_ttb_st", "a\u035Cb", "st", "ttb", 0.02),
# extends to the left (fail=0.064)
("overline", "i\u0305", None, None, 0.02),
("overline_la", "i\u0305", "la", None, 0.02),
("overline_ra", "i\u0305", "ra", None, 0.02),
("overline_ttb", "i\u0305", None, "ttb", 0.02),
("overline_ttb_rt", "i\u0305", "rt", "ttb", 0.02),
("overline_ttb_mt", "i\u0305", "mt", "ttb", 0.02),
("overline_ttb_st", "i\u0305", "st", "ttb", 0.02),
)
# this tests various combining characters for anchor alignment and clipping
@pytest.mark.parametrize(
"name,text,anchor,dir,epsilon", combine_tests, ids=[r[0] for r in combine_tests]
)
def test_combine(name, text, dir, anchor, epsilon):
if (
distutils.version.StrictVersion(ImageFont.core.freetype2_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 = "Tests/images/test_combine_%s.png" % name
f = ImageFont.truetype("Tests/fonts/NotoSans-Regular.ttf", 48)
im = Image.new("RGB", (400, 400), "white")
d = ImageDraw.Draw(im)
d.line(((0, 200), (400, 200)), "gray")
d.line(((200, 0), (200, 400)), "gray")
try:
d.text((200, 200), text, fill="black", anchor=anchor, direction=dir, font=f)
except ValueError as ex:
if str(ex) == "libraqm 0.7 or greater required for 'ttb' direction":
pytest.skip("libraqm 0.7 or greater not available")
with Image.open(path) as expected:
assert_image_similar(im, expected, epsilon)

View File

@ -398,9 +398,9 @@ class ImageDraw:
max_width = max(max_width, line_width)
top = xy[1]
if anchor[1] == 'm':
if anchor[1] == "m":
top -= (len(lines) - 1) * line_spacing / 2.0
elif anchor[1] == 'd':
elif anchor[1] == "d":
top -= (len(lines) - 1) * line_spacing
for idx, line in enumerate(lines):
@ -408,9 +408,9 @@ class ImageDraw:
width_difference = max_width - widths[idx]
# first align left by anchor
if anchor[0] == 'm':
if anchor[0] == "m":
left -= width_difference / 2.0
elif anchor[0] == 'r':
elif anchor[0] == "r":
left -= width_difference
# then align by align parameter