Merge branch 'main' into multiline_centered_embedded_color

This commit is contained in:
Andrew Murray 2022-08-25 18:49:40 +10:00
commit fc3930cc4c
25 changed files with 1016 additions and 1032 deletions

View File

@ -35,7 +35,6 @@ python3 -m pip install -U pytest
python3 -m pip install -U pytest-cov python3 -m pip install -U pytest-cov
python3 -m pip install -U pytest-timeout python3 -m pip install -U pytest-timeout
python3 -m pip install pyroma python3 -m pip install pyroma
python3 -m pip install test-image-results
if [[ $(uname) != CYGWIN* ]]; then if [[ $(uname) != CYGWIN* ]]; then
# TODO Remove condition when NumPy supports 3.11 # TODO Remove condition when NumPy supports 3.11

View File

@ -12,7 +12,6 @@ python3 -m pip install -U pytest
python3 -m pip install -U pytest-cov python3 -m pip install -U pytest-cov
python3 -m pip install -U pytest-timeout python3 -m pip install -U pytest-timeout
python3 -m pip install pyroma python3 -m pip install pyroma
python3 -m pip install test-image-results
echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openblas/lib" >> ~/.numpy-site.cfg echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openblas/lib" >> ~/.numpy-site.cfg
# TODO Remove condition when NumPy supports 3.11 # TODO Remove condition when NumPy supports 3.11

View File

@ -325,8 +325,9 @@ def test_apng_syntax_errors():
pytest.warns(UserWarning, open) pytest.warns(UserWarning, open)
def test_apng_sequence_errors(): @pytest.mark.parametrize(
test_files = [ "test_file",
(
"sequence_start.png", "sequence_start.png",
"sequence_gap.png", "sequence_gap.png",
"sequence_repeat.png", "sequence_repeat.png",
@ -334,10 +335,11 @@ def test_apng_sequence_errors():
"sequence_reorder.png", "sequence_reorder.png",
"sequence_reorder_chunk.png", "sequence_reorder_chunk.png",
"sequence_fdat_fctl.png", "sequence_fdat_fctl.png",
] ),
for f in test_files: )
def test_apng_sequence_errors(test_file):
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
with Image.open(f"Tests/images/apng/{f}") as im: with Image.open(f"Tests/images/apng/{test_file}") as im:
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
im.load() im.load()

View File

@ -1,3 +1,5 @@
import pytest
from PIL import ContainerIO, Image from PIL import ContainerIO, Image
from .helper import hopper from .helper import hopper
@ -59,9 +61,9 @@ def test_seek_mode_2():
assert container.tell() == 100 assert container.tell() == 100
def test_read_n0(): @pytest.mark.parametrize("bytesmode", (True, False))
def test_read_n0(bytesmode):
# Arrange # Arrange
for bytesmode in (True, False):
with open(TEST_FILE, "rb" if bytesmode else "r") as fh: with open(TEST_FILE, "rb" if bytesmode else "r") as fh:
container = ContainerIO.ContainerIO(fh, 22, 100) container = ContainerIO.ContainerIO(fh, 22, 100)
@ -75,9 +77,9 @@ def test_read_n0():
assert data == "7\nThis is line 8\n" assert data == "7\nThis is line 8\n"
def test_read_n(): @pytest.mark.parametrize("bytesmode", (True, False))
def test_read_n(bytesmode):
# Arrange # Arrange
for bytesmode in (True, False):
with open(TEST_FILE, "rb" if bytesmode else "r") as fh: with open(TEST_FILE, "rb" if bytesmode else "r") as fh:
container = ContainerIO.ContainerIO(fh, 22, 100) container = ContainerIO.ContainerIO(fh, 22, 100)
@ -91,9 +93,9 @@ def test_read_n():
assert data == "7\nT" assert data == "7\nT"
def test_read_eof(): @pytest.mark.parametrize("bytesmode", (True, False))
def test_read_eof(bytesmode):
# Arrange # Arrange
for bytesmode in (True, False):
with open(TEST_FILE, "rb" if bytesmode else "r") as fh: with open(TEST_FILE, "rb" if bytesmode else "r") as fh:
container = ContainerIO.ContainerIO(fh, 22, 100) container = ContainerIO.ContainerIO(fh, 22, 100)
@ -107,9 +109,9 @@ def test_read_eof():
assert data == "" assert data == ""
def test_readline(): @pytest.mark.parametrize("bytesmode", (True, False))
def test_readline(bytesmode):
# Arrange # Arrange
for bytesmode in (True, False):
with open(TEST_FILE, "rb" if bytesmode else "r") as fh: with open(TEST_FILE, "rb" if bytesmode else "r") as fh:
container = ContainerIO.ContainerIO(fh, 0, 120) container = ContainerIO.ContainerIO(fh, 0, 120)
@ -122,9 +124,9 @@ def test_readline():
assert data == "This is line 1\n" assert data == "This is line 1\n"
def test_readlines(): @pytest.mark.parametrize("bytesmode", (True, False))
def test_readlines(bytesmode):
# Arrange # Arrange
for bytesmode in (True, False):
expected = [ expected = [
"This is line 1\n", "This is line 1\n",
"This is line 2\n", "This is line 2\n",

View File

@ -78,16 +78,13 @@ def test_eoferror():
im.seek(n_frames - 1) im.seek(n_frames - 1)
def test_roundtrip(tmp_path): @pytest.mark.parametrize("mode", ("RGB", "P", "PA"))
def roundtrip(mode): def test_roundtrip(mode, tmp_path):
out = str(tmp_path / "temp.im") out = str(tmp_path / "temp.im")
im = hopper(mode) im = hopper(mode)
im.save(out) im.save(out)
assert_image_equal_tofile(im, out) assert_image_equal_tofile(im, out)
for mode in ["RGB", "P", "PA"]:
roundtrip(mode)
def test_save_unsupported_mode(tmp_path): def test_save_unsupported_mode(tmp_path):
out = str(tmp_path / "temp.im") out = str(tmp_path / "temp.im")

View File

@ -135,9 +135,9 @@ class TestFileLibTiff(LibTiffTestCase):
assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_write_metadata(self, tmp_path): @pytest.mark.parametrize("legacy_api", (False, True))
def test_write_metadata(self, legacy_api, tmp_path):
"""Test metadata writing through libtiff""" """Test metadata writing through libtiff"""
for legacy_api in [False, True]:
f = str(tmp_path / "temp.tiff") f = str(tmp_path / "temp.tiff")
with Image.open("Tests/images/hopper_g4.tif") as img: with Image.open("Tests/images/hopper_g4.tif") as img:
img.save(f, tiffinfo=img.tag) img.save(f, tiffinfo=img.tag)

View File

@ -27,8 +27,8 @@ def roundtrip(im, **options):
return im return im
def test_sanity(): @pytest.mark.parametrize("test_file", test_files)
for test_file in test_files: def test_sanity(test_file):
with Image.open(test_file) as im: with Image.open(test_file) as im:
im.load() im.load()
assert im.mode == "RGB" assert im.mode == "RGB"
@ -66,21 +66,20 @@ def test_context_manager():
im.load() im.load()
def test_app(): @pytest.mark.parametrize("test_file", test_files)
for test_file in test_files: def test_app(test_file):
# Test APP/COM reader (@PIL135) # Test APP/COM reader (@PIL135)
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.applist[0][0] == "APP1" assert im.applist[0][0] == "APP1"
assert im.applist[1][0] == "APP2" assert im.applist[1][0] == "APP2"
assert ( assert (
im.applist[1][1][:16] im.applist[1][1][:16] == b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00"
== b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00"
) )
assert len(im.applist) == 2 assert len(im.applist) == 2
def test_exif(): @pytest.mark.parametrize("test_file", test_files)
for test_file in test_files: def test_exif(test_file):
with Image.open(test_file) as im: with Image.open(test_file) as im:
info = im._getexif() info = im._getexif()
assert info[272] == "Nintendo 3DS" assert info[272] == "Nintendo 3DS"
@ -137,8 +136,8 @@ def test_reload_exif_after_seek():
assert 296 in exif assert 296 in exif
def test_mp(): @pytest.mark.parametrize("test_file", test_files)
for test_file in test_files: def test_mp(test_file):
with Image.open(test_file) as im: with Image.open(test_file) as im:
mpinfo = im._getmp() mpinfo = im._getmp()
assert mpinfo[45056] == b"0100" assert mpinfo[45056] == b"0100"
@ -162,8 +161,8 @@ def test_mp_no_data():
im.seek(1) im.seek(1)
def test_mp_attribute(): @pytest.mark.parametrize("test_file", test_files)
for test_file in test_files: def test_mp_attribute(test_file):
with Image.open(test_file) as im: with Image.open(test_file) as im:
mpinfo = im._getmp() mpinfo = im._getmp()
frame_number = 0 frame_number = 0
@ -181,8 +180,8 @@ def test_mp_attribute():
frame_number += 1 frame_number += 1
def test_seek(): @pytest.mark.parametrize("test_file", test_files)
for test_file in test_files: def test_seek(test_file):
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.tell() == 0 assert im.tell() == 0
# prior to first image raises an error, both blatant and borderline # prior to first image raises an error, both blatant and borderline
@ -225,8 +224,8 @@ def test_eoferror():
im.seek(n_frames - 1) im.seek(n_frames - 1)
def test_image_grab(): @pytest.mark.parametrize("test_file", test_files)
for test_file in test_files: def test_image_grab(test_file):
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.tell() == 0 assert im.tell() == 0
im0 = im.tobytes() im0 = im.tobytes()
@ -240,8 +239,8 @@ def test_image_grab():
assert im0 != im1 assert im0 != im1
def test_save(): @pytest.mark.parametrize("test_file", test_files)
for test_file in test_files: def test_save(test_file):
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.tell() == 0 assert im.tell() == 0
jpg0 = roundtrip(im) jpg0 = roundtrip(im)

View File

@ -37,6 +37,7 @@ def helper_save_as_pdf(tmp_path, mode, **kwargs):
return outfile return outfile
@pytest.mark.valgrind_known_error(reason="Temporary skip")
def test_monochrome(tmp_path): def test_monochrome(tmp_path):
# Arrange # Arrange
mode = "1" mode = "1"

View File

@ -18,18 +18,15 @@ _ORIGINS = ("tl", "bl")
_ORIGIN_TO_ORIENTATION = {"tl": 1, "bl": -1} _ORIGIN_TO_ORIENTATION = {"tl": 1, "bl": -1}
def test_sanity(tmp_path): @pytest.mark.parametrize("mode", _MODES)
for mode in _MODES: def test_sanity(mode, tmp_path):
def roundtrip(original_im): def roundtrip(original_im):
out = str(tmp_path / "temp.tga") out = str(tmp_path / "temp.tga")
original_im.save(out, rle=rle) original_im.save(out, rle=rle)
with Image.open(out) as saved_im: with Image.open(out) as saved_im:
if rle: if rle:
assert ( assert saved_im.info["compression"] == original_im.info["compression"]
saved_im.info["compression"] == original_im.info["compression"]
)
assert saved_im.info["orientation"] == original_im.info["orientation"] assert saved_im.info["orientation"] == original_im.info["orientation"]
if mode == "P": if mode == "P":
assert saved_im.getpalette() == original_im.getpalette() assert saved_im.getpalette() == original_im.getpalette()

View File

@ -66,10 +66,10 @@ def test_load_set_dpi():
assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref_144.png", 2.1) assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref_144.png", 2.1)
def test_save(tmp_path): @pytest.mark.parametrize("ext", (".wmf", ".emf"))
def test_save(ext, tmp_path):
im = hopper() im = hopper()
for ext in [".wmf", ".emf"]:
tmpfile = str(tmp_path / ("temp" + ext)) tmpfile = str(tmp_path / ("temp" + ext))
with pytest.raises(OSError): with pytest.raises(OSError):
im.save(tmpfile) im.save(tmpfile)

View File

@ -22,8 +22,9 @@ from .helper import (
class TestImage: class TestImage:
def test_image_modes_success(self): @pytest.mark.parametrize(
for mode in [ "mode",
(
"1", "1",
"P", "P",
"PA", "PA",
@ -44,19 +45,15 @@ class TestImage:
"YCbCr", "YCbCr",
"LAB", "LAB",
"HSV", "HSV",
]: ),
)
def test_image_modes_success(self, mode):
Image.new(mode, (1, 1)) Image.new(mode, (1, 1))
def test_image_modes_fail(self): @pytest.mark.parametrize(
for mode in [ "mode", ("", "bad", "very very long", "BGR;15", "BGR;16", "BGR;24", "BGR;32")
"", )
"bad", def test_image_modes_fail(self, mode):
"very very long",
"BGR;15",
"BGR;16",
"BGR;24",
"BGR;32",
]:
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
Image.new(mode, (1, 1)) Image.new(mode, (1, 1))
assert str(e.value) == "unrecognized image mode" assert str(e.value) == "unrecognized image mode"
@ -539,11 +536,10 @@ class TestImage:
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.linear_gradient(wrong_mode) Image.linear_gradient(wrong_mode)
def test_linear_gradient(self): @pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
def test_linear_gradient(self, mode):
# Arrange # Arrange
target_file = "Tests/images/linear_gradient.png" target_file = "Tests/images/linear_gradient.png"
for mode in ["L", "P", "I", "F"]:
# Act # Act
im = Image.linear_gradient(mode) im = Image.linear_gradient(mode)
@ -565,11 +561,10 @@ class TestImage:
with pytest.raises(ValueError): with pytest.raises(ValueError):
Image.radial_gradient(wrong_mode) Image.radial_gradient(wrong_mode)
def test_radial_gradient(self): @pytest.mark.parametrize("mode", ("L", "P", "I", "F"))
def test_radial_gradient(self, mode):
# Arrange # Arrange
target_file = "Tests/images/radial_gradient.png" target_file = "Tests/images/radial_gradient.png"
for mode in ["L", "P", "I", "F"]:
# Act # Act
im = Image.radial_gradient(mode) im = Image.radial_gradient(mode)

View File

@ -184,8 +184,9 @@ class TestImageGetPixel(AccessTest):
with pytest.raises(error): with pytest.raises(error):
im.getpixel((-1, -1)) im.getpixel((-1, -1))
def test_basic(self): @pytest.mark.parametrize(
for mode in ( "mode",
(
"1", "1",
"L", "L",
"LA", "LA",
@ -200,20 +201,22 @@ class TestImageGetPixel(AccessTest):
"RGBX", "RGBX",
"CMYK", "CMYK",
"YCbCr", "YCbCr",
): ),
)
def test_basic(self, mode):
self.check(mode) self.check(mode)
def test_signedness(self): @pytest.mark.parametrize("mode", ("I;16", "I;16B"))
def test_signedness(self, mode):
# see https://github.com/python-pillow/Pillow/issues/452 # see https://github.com/python-pillow/Pillow/issues/452
# pixelaccess is using signed int* instead of uint* # pixelaccess is using signed int* instead of uint*
for mode in ("I;16", "I;16B"):
self.check(mode, 2**15 - 1) self.check(mode, 2**15 - 1)
self.check(mode, 2**15) self.check(mode, 2**15)
self.check(mode, 2**15 + 1) self.check(mode, 2**15 + 1)
self.check(mode, 2**16 - 1) self.check(mode, 2**16 - 1)
def test_p_putpixel_rgb_rgba(self): @pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255)))
for color in [(255, 0, 0), (255, 0, 0, 255)]: def test_p_putpixel_rgb_rgba(self, color):
im = Image.new("P", (1, 1), 0) im = Image.new("P", (1, 1), 0)
im.putpixel((0, 0), color) im.putpixel((0, 0), color)
assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0) assert im.convert("RGB").getpixel((0, 0)) == (255, 0, 0)

View File

@ -268,8 +268,8 @@ def test_matrix_wrong_mode():
im.convert(mode="L", matrix=matrix) im.convert(mode="L", matrix=matrix)
def test_matrix_xyz(): @pytest.mark.parametrize("mode", ("RGB", "L"))
def matrix_convert(mode): def test_matrix_xyz(mode):
# Arrange # Arrange
im = hopper("RGB") im = hopper("RGB")
im.info["transparency"] = (255, 0, 0) im.info["transparency"] = (255, 0, 0)
@ -296,9 +296,6 @@ def test_matrix_xyz():
assert_image_similar(converted_im, target.getchannel(0), 1) assert_image_similar(converted_im, target.getchannel(0), 1)
assert converted_im.info["transparency"] == 105 assert converted_im.info["transparency"] == 105
matrix_convert("RGB")
matrix_convert("L")
def test_matrix_identity(): def test_matrix_identity():
# Arrange # Arrange

View File

@ -1,14 +1,17 @@
import copy import copy
import pytest
from PIL import Image from PIL import Image
from .helper import hopper from .helper import hopper
def test_copy(): @pytest.mark.parametrize("mode", ("1", "P", "L", "RGB", "I", "F"))
def test_copy(mode):
cropped_coordinates = (10, 10, 20, 20) cropped_coordinates = (10, 10, 20, 20)
cropped_size = (10, 10) cropped_size = (10, 10)
for mode in "1", "P", "L", "RGB", "I", "F":
# Internal copy method # Internal copy method
im = hopper(mode) im = hopper(mode)
out = im.copy() out = im.copy()

View File

@ -5,8 +5,8 @@ from PIL import Image
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
def test_crop(): @pytest.mark.parametrize("mode", ("1", "P", "L", "RGB", "I", "F"))
def crop(mode): def test_crop(mode):
im = hopper(mode) im = hopper(mode)
assert_image_equal(im.crop(), im) assert_image_equal(im.crop(), im)
@ -14,9 +14,6 @@ def test_crop():
assert cropped.mode == mode assert cropped.mode == mode
assert cropped.size == (50, 50) assert cropped.size == (50, 50)
for mode in "1", "P", "L", "RGB", "I", "F":
crop(mode)
def test_wide_crop(): def test_wide_crop():
def crop(*bbox): def crop(*bbox):

View File

@ -1,3 +1,5 @@
import pytest
from PIL import Image from PIL import Image
from .helper import CachedProperty, assert_image_equal from .helper import CachedProperty, assert_image_equal
@ -101,8 +103,8 @@ class TestImagingPaste:
], ],
) )
def test_image_solid(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_image_solid(self, mode):
im = Image.new(mode, (200, 200), "red") im = Image.new(mode, (200, 200), "red")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -111,8 +113,8 @@ class TestImagingPaste:
im = im.crop((12, 23, im2.width + 12, im2.height + 23)) im = im.crop((12, 23, im2.width + 12, im2.height + 23))
assert_image_equal(im, im2) assert_image_equal(im, im2)
def test_image_mask_1(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_image_mask_1(self, mode):
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -133,8 +135,8 @@ class TestImagingPaste:
], ],
) )
def test_image_mask_L(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_image_mask_L(self, mode):
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -155,8 +157,8 @@ class TestImagingPaste:
], ],
) )
def test_image_mask_LA(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_image_mask_LA(self, mode):
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -177,8 +179,8 @@ class TestImagingPaste:
], ],
) )
def test_image_mask_RGBA(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_image_mask_RGBA(self, mode):
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -199,8 +201,8 @@ class TestImagingPaste:
], ],
) )
def test_image_mask_RGBa(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_image_mask_RGBa(self, mode):
im = Image.new(mode, (200, 200), "white") im = Image.new(mode, (200, 200), "white")
im2 = getattr(self, "gradient_" + mode) im2 = getattr(self, "gradient_" + mode)
@ -221,8 +223,8 @@ class TestImagingPaste:
], ],
) )
def test_color_solid(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_color_solid(self, mode):
im = Image.new(mode, (200, 200), "black") im = Image.new(mode, (200, 200), "black")
rect = (12, 23, 128 + 12, 128 + 23) rect = (12, 23, 128 + 12, 128 + 23)
@ -234,8 +236,8 @@ class TestImagingPaste:
assert head[255] == 128 * 128 assert head[255] == 128 * 128
assert sum(head[:255]) == 0 assert sum(head[:255]) == 0
def test_color_mask_1(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_color_mask_1(self, mode):
im = Image.new(mode, (200, 200), (50, 60, 70, 80)[: len(mode)]) im = Image.new(mode, (200, 200), (50, 60, 70, 80)[: len(mode)])
color = (10, 20, 30, 40)[: len(mode)] color = (10, 20, 30, 40)[: len(mode)]
@ -256,8 +258,8 @@ class TestImagingPaste:
], ],
) )
def test_color_mask_L(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_color_mask_L(self, mode):
im = getattr(self, "gradient_" + mode).copy() im = getattr(self, "gradient_" + mode).copy()
color = "white" color = "white"
@ -278,8 +280,8 @@ class TestImagingPaste:
], ],
) )
def test_color_mask_RGBA(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_color_mask_RGBA(self, mode):
im = getattr(self, "gradient_" + mode).copy() im = getattr(self, "gradient_" + mode).copy()
color = "white" color = "white"
@ -300,8 +302,8 @@ class TestImagingPaste:
], ],
) )
def test_color_mask_RGBa(self): @pytest.mark.parametrize("mode", ["RGBA", "RGB", "L"])
for mode in ("RGBA", "RGB", "L"): def test_color_mask_RGBa(self, mode):
im = getattr(self, "gradient_" + mode).copy() im = getattr(self, "gradient_" + mode).copy()
color = "white" color = "white"

View File

@ -100,8 +100,8 @@ class TestImagingCoreResampleAccuracy:
for y in range(image.size[1]) for y in range(image.size[1])
) )
def test_reduce_box(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
for mode in ["RGBX", "RGB", "La", "L"]: def test_reduce_box(self, mode):
case = self.make_case(mode, (8, 8), 0xE1) case = self.make_case(mode, (8, 8), 0xE1)
case = case.resize((4, 4), Image.Resampling.BOX) case = case.resize((4, 4), Image.Resampling.BOX)
# fmt: off # fmt: off
@ -111,8 +111,8 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
def test_reduce_bilinear(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
for mode in ["RGBX", "RGB", "La", "L"]: def test_reduce_bilinear(self, mode):
case = self.make_case(mode, (8, 8), 0xE1) case = self.make_case(mode, (8, 8), 0xE1)
case = case.resize((4, 4), Image.Resampling.BILINEAR) case = case.resize((4, 4), Image.Resampling.BILINEAR)
# fmt: off # fmt: off
@ -122,8 +122,8 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
def test_reduce_hamming(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
for mode in ["RGBX", "RGB", "La", "L"]: def test_reduce_hamming(self, mode):
case = self.make_case(mode, (8, 8), 0xE1) case = self.make_case(mode, (8, 8), 0xE1)
case = case.resize((4, 4), Image.Resampling.HAMMING) case = case.resize((4, 4), Image.Resampling.HAMMING)
# fmt: off # fmt: off
@ -133,7 +133,8 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
def test_reduce_bicubic(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
def test_reduce_bicubic(self, mode):
for mode in ["RGBX", "RGB", "La", "L"]: for mode in ["RGBX", "RGB", "La", "L"]:
case = self.make_case(mode, (12, 12), 0xE1) case = self.make_case(mode, (12, 12), 0xE1)
case = case.resize((6, 6), Image.Resampling.BICUBIC) case = case.resize((6, 6), Image.Resampling.BICUBIC)
@ -145,8 +146,8 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (6, 6))) self.check_case(channel, self.make_sample(data, (6, 6)))
def test_reduce_lanczos(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
for mode in ["RGBX", "RGB", "La", "L"]: def test_reduce_lanczos(self, mode):
case = self.make_case(mode, (16, 16), 0xE1) case = self.make_case(mode, (16, 16), 0xE1)
case = case.resize((8, 8), Image.Resampling.LANCZOS) case = case.resize((8, 8), Image.Resampling.LANCZOS)
# fmt: off # fmt: off
@ -158,8 +159,8 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (8, 8))) self.check_case(channel, self.make_sample(data, (8, 8)))
def test_enlarge_box(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
for mode in ["RGBX", "RGB", "La", "L"]: def test_enlarge_box(self, mode):
case = self.make_case(mode, (2, 2), 0xE1) case = self.make_case(mode, (2, 2), 0xE1)
case = case.resize((4, 4), Image.Resampling.BOX) case = case.resize((4, 4), Image.Resampling.BOX)
# fmt: off # fmt: off
@ -169,8 +170,8 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
def test_enlarge_bilinear(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
for mode in ["RGBX", "RGB", "La", "L"]: def test_enlarge_bilinear(self, mode):
case = self.make_case(mode, (2, 2), 0xE1) case = self.make_case(mode, (2, 2), 0xE1)
case = case.resize((4, 4), Image.Resampling.BILINEAR) case = case.resize((4, 4), Image.Resampling.BILINEAR)
# fmt: off # fmt: off
@ -180,8 +181,8 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
def test_enlarge_hamming(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
for mode in ["RGBX", "RGB", "La", "L"]: def test_enlarge_hamming(self, mode):
case = self.make_case(mode, (2, 2), 0xE1) case = self.make_case(mode, (2, 2), 0xE1)
case = case.resize((4, 4), Image.Resampling.HAMMING) case = case.resize((4, 4), Image.Resampling.HAMMING)
# fmt: off # fmt: off
@ -191,8 +192,8 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (4, 4))) self.check_case(channel, self.make_sample(data, (4, 4)))
def test_enlarge_bicubic(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
for mode in ["RGBX", "RGB", "La", "L"]: def test_enlarge_bicubic(self, mode):
case = self.make_case(mode, (4, 4), 0xE1) case = self.make_case(mode, (4, 4), 0xE1)
case = case.resize((8, 8), Image.Resampling.BICUBIC) case = case.resize((8, 8), Image.Resampling.BICUBIC)
# fmt: off # fmt: off
@ -204,8 +205,8 @@ class TestImagingCoreResampleAccuracy:
for channel in case.split(): for channel in case.split():
self.check_case(channel, self.make_sample(data, (8, 8))) self.check_case(channel, self.make_sample(data, (8, 8)))
def test_enlarge_lanczos(self): @pytest.mark.parametrize("mode", ("RGBX", "RGB", "La", "L"))
for mode in ["RGBX", "RGB", "La", "L"]: def test_enlarge_lanczos(self, mode):
case = self.make_case(mode, (6, 6), 0xE1) case = self.make_case(mode, (6, 6), 0xE1)
case = case.resize((12, 12), Image.Resampling.LANCZOS) case = case.resize((12, 12), Image.Resampling.LANCZOS)
data = ( data = (
@ -419,16 +420,19 @@ class TestCoreResampleCoefficients:
class TestCoreResampleBox: class TestCoreResampleBox:
def test_wrong_arguments(self): @pytest.mark.parametrize(
im = hopper() "resample",
for resample in ( (
Image.Resampling.NEAREST, Image.Resampling.NEAREST,
Image.Resampling.BOX, Image.Resampling.BOX,
Image.Resampling.BILINEAR, Image.Resampling.BILINEAR,
Image.Resampling.HAMMING, Image.Resampling.HAMMING,
Image.Resampling.BICUBIC, Image.Resampling.BICUBIC,
Image.Resampling.LANCZOS, Image.Resampling.LANCZOS,
): ),
)
def test_wrong_arguments(self, resample):
im = hopper()
im.resize((32, 32), resample, (0, 0, im.width, im.height)) im.resize((32, 32), resample, (0, 0, im.width, im.height))
im.resize((32, 32), resample, (20, 20, im.width, im.height)) im.resize((32, 32), resample, (20, 20, im.width, im.height))
im.resize((32, 32), resample, (20, 20, 20, 100)) im.resize((32, 32), resample, (20, 20, 20, 100))
@ -509,9 +513,11 @@ class TestCoreResampleBox:
with pytest.raises(AssertionError, match=r"difference 29\."): with pytest.raises(AssertionError, match=r"difference 29\."):
assert_image_similar(reference, without_box, 5) assert_image_similar(reference, without_box, 5)
def test_formats(self): @pytest.mark.parametrize("mode", ("RGB", "L", "RGBA", "LA", "I", ""))
for resample in [Image.Resampling.NEAREST, Image.Resampling.BILINEAR]: @pytest.mark.parametrize(
for mode in ["RGB", "L", "RGBA", "LA", "I", ""]: "resample", (Image.Resampling.NEAREST, Image.Resampling.BILINEAR)
)
def test_formats(self, mode, resample):
im = hopper(mode) im = hopper(mode)
box = (20, 20, im.size[0] - 20, im.size[1] - 20) box = (20, 20, im.size[0] - 20, im.size[1] - 20)
with_box = im.resize((32, 32), resample, box) with_box = im.resize((32, 32), resample, box)

View File

@ -22,19 +22,10 @@ class TestImagingCoreResize:
im.load() im.load()
return im._new(im.im.resize(size, f)) return im._new(im.im.resize(size, f))
def test_nearest_mode(self): @pytest.mark.parametrize(
for mode in [ "mode", ("1", "P", "L", "I", "F", "RGB", "RGBA", "CMYK", "YCbCr", "I;16")
"1", )
"P", def test_nearest_mode(self, mode):
"L",
"I",
"F",
"RGB",
"RGBA",
"CMYK",
"YCbCr",
"I;16",
]: # exotic mode
im = hopper(mode) im = hopper(mode)
r = self.resize(im, (15, 12), Image.Resampling.NEAREST) r = self.resize(im, (15, 12), Image.Resampling.NEAREST)
assert r.mode == mode assert r.mode == mode
@ -55,33 +46,58 @@ class TestImagingCoreResize:
assert r.size == (15, 12) assert r.size == (15, 12)
assert r.im.bands == im.im.bands assert r.im.bands == im.im.bands
def test_reduce_filters(self): @pytest.mark.parametrize(
for f in [ "resample",
(
Image.Resampling.NEAREST, Image.Resampling.NEAREST,
Image.Resampling.BOX, Image.Resampling.BOX,
Image.Resampling.BILINEAR, Image.Resampling.BILINEAR,
Image.Resampling.HAMMING, Image.Resampling.HAMMING,
Image.Resampling.BICUBIC, Image.Resampling.BICUBIC,
Image.Resampling.LANCZOS, Image.Resampling.LANCZOS,
]: ),
r = self.resize(hopper("RGB"), (15, 12), f) )
def test_reduce_filters(self, resample):
r = self.resize(hopper("RGB"), (15, 12), resample)
assert r.mode == "RGB" assert r.mode == "RGB"
assert r.size == (15, 12) assert r.size == (15, 12)
def test_enlarge_filters(self): @pytest.mark.parametrize(
for f in [ "resample",
(
Image.Resampling.NEAREST, Image.Resampling.NEAREST,
Image.Resampling.BOX, Image.Resampling.BOX,
Image.Resampling.BILINEAR, Image.Resampling.BILINEAR,
Image.Resampling.HAMMING, Image.Resampling.HAMMING,
Image.Resampling.BICUBIC, Image.Resampling.BICUBIC,
Image.Resampling.LANCZOS, Image.Resampling.LANCZOS,
]: ),
r = self.resize(hopper("RGB"), (212, 195), f) )
def test_enlarge_filters(self, resample):
r = self.resize(hopper("RGB"), (212, 195), resample)
assert r.mode == "RGB" assert r.mode == "RGB"
assert r.size == (212, 195) assert r.size == (212, 195)
def test_endianness(self): @pytest.mark.parametrize(
"resample",
(
Image.Resampling.NEAREST,
Image.Resampling.BOX,
Image.Resampling.BILINEAR,
Image.Resampling.HAMMING,
Image.Resampling.BICUBIC,
Image.Resampling.LANCZOS,
),
)
@pytest.mark.parametrize(
"mode, channels_set",
(
("RGB", ("blank", "filled", "dirty")),
("RGBA", ("blank", "blank", "filled", "dirty")),
("LA", ("filled", "dirty")),
),
)
def test_endianness(self, resample, mode, channels_set):
# Make an image with one colored pixel, in one channel. # Make an image with one colored pixel, in one channel.
# When resized, that channel should be the same as a GS image. # When resized, that channel should be the same as a GS image.
# Other channels should be unaffected. # Other channels should be unaffected.
@ -95,44 +111,34 @@ class TestImagingCoreResize:
} }
samples["dirty"].putpixel((1, 1), 128) samples["dirty"].putpixel((1, 1), 128)
for f in [
Image.Resampling.NEAREST,
Image.Resampling.BOX,
Image.Resampling.BILINEAR,
Image.Resampling.HAMMING,
Image.Resampling.BICUBIC,
Image.Resampling.LANCZOS,
]:
# samples resized with current filter # samples resized with current filter
references = { references = {
name: self.resize(ch, (4, 4), f) for name, ch in samples.items() name: self.resize(ch, (4, 4), resample) for name, ch in samples.items()
} }
for mode, channels_set in [
("RGB", ("blank", "filled", "dirty")),
("RGBA", ("blank", "blank", "filled", "dirty")),
("LA", ("filled", "dirty")),
]:
for channels in set(permutations(channels_set)): for channels in set(permutations(channels_set)):
# compile image from different channels permutations # compile image from different channels permutations
im = Image.merge(mode, [samples[ch] for ch in channels]) im = Image.merge(mode, [samples[ch] for ch in channels])
resized = self.resize(im, (4, 4), f) resized = self.resize(im, (4, 4), resample)
for i, ch in enumerate(resized.split()): for i, ch in enumerate(resized.split()):
# check what resized channel in image is the same # check what resized channel in image is the same
# as separately resized channel # as separately resized channel
assert_image_equal(ch, references[channels[i]]) assert_image_equal(ch, references[channels[i]])
def test_enlarge_zero(self): @pytest.mark.parametrize(
for f in [ "resample",
(
Image.Resampling.NEAREST, Image.Resampling.NEAREST,
Image.Resampling.BOX, Image.Resampling.BOX,
Image.Resampling.BILINEAR, Image.Resampling.BILINEAR,
Image.Resampling.HAMMING, Image.Resampling.HAMMING,
Image.Resampling.BICUBIC, Image.Resampling.BICUBIC,
Image.Resampling.LANCZOS, Image.Resampling.LANCZOS,
]: ),
r = self.resize(Image.new("RGB", (0, 0), "white"), (212, 195), f) )
def test_enlarge_zero(self, resample):
r = self.resize(Image.new("RGB", (0, 0), "white"), (212, 195), resample)
assert r.mode == "RGB" assert r.mode == "RGB"
assert r.size == (212, 195) assert r.size == (212, 195)
assert r.getdata()[0] == (0, 0, 0) assert r.getdata()[0] == (0, 0, 0)
@ -179,12 +185,11 @@ class TestReducingGapResize:
(52, 34), Image.Resampling.BICUBIC, reducing_gap=0.99 (52, 34), Image.Resampling.BICUBIC, reducing_gap=0.99
) )
def test_reducing_gap_1(self, gradients_image): @pytest.mark.parametrize(
for box, epsilon in [ "box, epsilon",
(None, 4), ((None, 4), ((1.1, 2.2, 510.8, 510.9), 4), ((3, 10, 410, 256), 10)),
((1.1, 2.2, 510.8, 510.9), 4), )
((3, 10, 410, 256), 10), def test_reducing_gap_1(self, gradients_image, box, epsilon):
]:
ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box) ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box)
im = gradients_image.resize( im = gradients_image.resize(
(52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=1.0 (52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=1.0
@ -195,12 +200,11 @@ class TestReducingGapResize:
assert_image_similar(ref, im, epsilon) assert_image_similar(ref, im, epsilon)
def test_reducing_gap_2(self, gradients_image): @pytest.mark.parametrize(
for box, epsilon in [ "box, epsilon",
(None, 1.5), ((None, 1.5), ((1.1, 2.2, 510.8, 510.9), 1.5), ((3, 10, 410, 256), 1)),
((1.1, 2.2, 510.8, 510.9), 1.5), )
((3, 10, 410, 256), 1), def test_reducing_gap_2(self, gradients_image, box, epsilon):
]:
ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box) ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box)
im = gradients_image.resize( im = gradients_image.resize(
(52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=2.0 (52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=2.0
@ -211,12 +215,11 @@ class TestReducingGapResize:
assert_image_similar(ref, im, epsilon) assert_image_similar(ref, im, epsilon)
def test_reducing_gap_3(self, gradients_image): @pytest.mark.parametrize(
for box, epsilon in [ "box, epsilon",
(None, 1), ((None, 1), ((1.1, 2.2, 510.8, 510.9), 1), ((3, 10, 410, 256), 0.5)),
((1.1, 2.2, 510.8, 510.9), 1), )
((3, 10, 410, 256), 0.5), def test_reducing_gap_3(self, gradients_image, box, epsilon):
]:
ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box) ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box)
im = gradients_image.resize( im = gradients_image.resize(
(52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=3.0 (52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=3.0
@ -227,8 +230,8 @@ class TestReducingGapResize:
assert_image_similar(ref, im, epsilon) assert_image_similar(ref, im, epsilon)
def test_reducing_gap_8(self, gradients_image): @pytest.mark.parametrize("box", (None, (1.1, 2.2, 510.8, 510.9), (3, 10, 410, 256)))
for box in [None, (1.1, 2.2, 510.8, 510.9), (3, 10, 410, 256)]: def test_reducing_gap_8(self, gradients_image, box):
ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box) ref = gradients_image.resize((52, 34), Image.Resampling.BICUBIC, box=box)
im = gradients_image.resize( im = gradients_image.resize(
(52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=8.0 (52, 34), Image.Resampling.BICUBIC, box=box, reducing_gap=8.0
@ -236,11 +239,11 @@ class TestReducingGapResize:
assert_image_equal(ref, im) assert_image_equal(ref, im)
def test_box_filter(self, gradients_image): @pytest.mark.parametrize(
for box, epsilon in [ "box, epsilon",
((0, 0, 512, 512), 5.5), (((0, 0, 512, 512), 5.5), ((0.9, 1.7, 128, 128), 9.5)),
((0.9, 1.7, 128, 128), 9.5), )
]: def test_box_filter(self, gradients_image, box, epsilon):
ref = gradients_image.resize((52, 34), Image.Resampling.BOX, box=box) ref = gradients_image.resize((52, 34), Image.Resampling.BOX, box=box)
im = gradients_image.resize( im = gradients_image.resize(
(52, 34), Image.Resampling.BOX, box=box, reducing_gap=1.0 (52, 34), Image.Resampling.BOX, box=box, reducing_gap=1.0
@ -273,15 +276,14 @@ class TestImageResize:
im = im.resize((64, 64)) im = im.resize((64, 64))
assert im.size == (64, 64) assert im.size == (64, 64)
def test_default_filter(self): @pytest.mark.parametrize("mode", ("L", "RGB", "I", "F"))
for mode in "L", "RGB", "I", "F": def test_default_filter_bicubic(self, mode):
im = hopper(mode) im = hopper(mode)
assert im.resize((20, 20), Image.Resampling.BICUBIC) == im.resize((20, 20)) assert im.resize((20, 20), Image.Resampling.BICUBIC) == im.resize((20, 20))
for mode in "1", "P": @pytest.mark.parametrize(
im = hopper(mode) "mode", ("1", "P", "I;16", "I;16L", "I;16B", "BGR;15", "BGR;16")
assert im.resize((20, 20), Image.Resampling.NEAREST) == im.resize((20, 20)) )
def test_default_filter_nearest(self, mode):
for mode in "I;16", "I;16L", "I;16B", "BGR;15", "BGR;16":
im = hopper(mode) im = hopper(mode)
assert im.resize((20, 20), Image.Resampling.NEAREST) == im.resize((20, 20)) assert im.resize((20, 20), Image.Resampling.NEAREST) == im.resize((20, 20))

View File

@ -1,3 +1,5 @@
import pytest
from PIL import Image from PIL import Image
from .helper import ( from .helper import (
@ -22,14 +24,14 @@ def rotate(im, mode, angle, center=None, translate=None):
assert out.size != im.size assert out.size != im.size
def test_mode(): @pytest.mark.parametrize("mode", ("1", "P", "L", "RGB", "I", "F"))
for mode in ("1", "P", "L", "RGB", "I", "F"): def test_mode(mode):
im = hopper(mode) im = hopper(mode)
rotate(im, mode, 45) rotate(im, mode, 45)
def test_angle(): @pytest.mark.parametrize("angle", (0, 90, 180, 270))
for angle in (0, 90, 180, 270): def test_angle(angle):
with Image.open("Tests/images/test-card.png") as im: with Image.open("Tests/images/test-card.png") as im:
rotate(im, im.mode, angle) rotate(im, im.mode, angle)
@ -37,8 +39,8 @@ def test_angle():
assert_image_equal(im.rotate(angle), im.rotate(angle, expand=1)) assert_image_equal(im.rotate(angle), im.rotate(angle, expand=1))
def test_zero(): @pytest.mark.parametrize("angle", (0, 45, 90, 180, 270))
for angle in (0, 45, 90, 180, 270): def test_zero(angle):
im = Image.new("RGB", (0, 0)) im = Image.new("RGB", (0, 0))
rotate(im, im.mode, angle) rotate(im, im.mode, angle)

View File

@ -1,3 +1,5 @@
import pytest
from PIL.Image import Transpose from PIL.Image import Transpose
from . import helper from . import helper
@ -9,8 +11,8 @@ HOPPER = {
} }
def test_flip_left_right(): @pytest.mark.parametrize("mode", HOPPER)
def transpose(mode): def test_flip_left_right(mode):
im = HOPPER[mode] im = HOPPER[mode]
out = im.transpose(Transpose.FLIP_LEFT_RIGHT) out = im.transpose(Transpose.FLIP_LEFT_RIGHT)
assert out.mode == mode assert out.mode == mode
@ -22,12 +24,9 @@ def test_flip_left_right():
assert im.getpixel((1, y - 2)) == out.getpixel((x - 2, y - 2)) assert im.getpixel((1, y - 2)) == out.getpixel((x - 2, y - 2))
assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, y - 2)) assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, y - 2))
for mode in HOPPER:
transpose(mode)
@pytest.mark.parametrize("mode", HOPPER)
def test_flip_top_bottom(): def test_flip_top_bottom(mode):
def transpose(mode):
im = HOPPER[mode] im = HOPPER[mode]
out = im.transpose(Transpose.FLIP_TOP_BOTTOM) out = im.transpose(Transpose.FLIP_TOP_BOTTOM)
assert out.mode == mode assert out.mode == mode
@ -39,12 +38,9 @@ def test_flip_top_bottom():
assert im.getpixel((1, y - 2)) == out.getpixel((1, 1)) assert im.getpixel((1, y - 2)) == out.getpixel((1, 1))
assert im.getpixel((x - 2, y - 2)) == out.getpixel((x - 2, 1)) assert im.getpixel((x - 2, y - 2)) == out.getpixel((x - 2, 1))
for mode in HOPPER:
transpose(mode)
@pytest.mark.parametrize("mode", HOPPER)
def test_rotate_90(): def test_rotate_90(mode):
def transpose(mode):
im = HOPPER[mode] im = HOPPER[mode]
out = im.transpose(Transpose.ROTATE_90) out = im.transpose(Transpose.ROTATE_90)
assert out.mode == mode assert out.mode == mode
@ -56,12 +52,9 @@ def test_rotate_90():
assert im.getpixel((1, y - 2)) == out.getpixel((y - 2, x - 2)) assert im.getpixel((1, y - 2)) == out.getpixel((y - 2, x - 2))
assert im.getpixel((x - 2, y - 2)) == out.getpixel((y - 2, 1)) assert im.getpixel((x - 2, y - 2)) == out.getpixel((y - 2, 1))
for mode in HOPPER:
transpose(mode)
@pytest.mark.parametrize("mode", HOPPER)
def test_rotate_180(): def test_rotate_180(mode):
def transpose(mode):
im = HOPPER[mode] im = HOPPER[mode]
out = im.transpose(Transpose.ROTATE_180) out = im.transpose(Transpose.ROTATE_180)
assert out.mode == mode assert out.mode == mode
@ -73,12 +66,9 @@ def test_rotate_180():
assert im.getpixel((1, y - 2)) == out.getpixel((x - 2, 1)) assert im.getpixel((1, y - 2)) == out.getpixel((x - 2, 1))
assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, 1)) assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, 1))
for mode in HOPPER:
transpose(mode)
@pytest.mark.parametrize("mode", HOPPER)
def test_rotate_270(): def test_rotate_270(mode):
def transpose(mode):
im = HOPPER[mode] im = HOPPER[mode]
out = im.transpose(Transpose.ROTATE_270) out = im.transpose(Transpose.ROTATE_270)
assert out.mode == mode assert out.mode == mode
@ -90,12 +80,9 @@ def test_rotate_270():
assert im.getpixel((1, y - 2)) == out.getpixel((1, 1)) assert im.getpixel((1, y - 2)) == out.getpixel((1, 1))
assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, x - 2)) assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, x - 2))
for mode in HOPPER:
transpose(mode)
@pytest.mark.parametrize("mode", HOPPER)
def test_transpose(): def test_transpose(mode):
def transpose(mode):
im = HOPPER[mode] im = HOPPER[mode]
out = im.transpose(Transpose.TRANSPOSE) out = im.transpose(Transpose.TRANSPOSE)
assert out.mode == mode assert out.mode == mode
@ -107,12 +94,9 @@ def test_transpose():
assert im.getpixel((1, y - 2)) == out.getpixel((y - 2, 1)) assert im.getpixel((1, y - 2)) == out.getpixel((y - 2, 1))
assert im.getpixel((x - 2, y - 2)) == out.getpixel((y - 2, x - 2)) assert im.getpixel((x - 2, y - 2)) == out.getpixel((y - 2, x - 2))
for mode in HOPPER:
transpose(mode)
@pytest.mark.parametrize("mode", HOPPER)
def test_tranverse(): def test_tranverse(mode):
def transpose(mode):
im = HOPPER[mode] im = HOPPER[mode]
out = im.transpose(Transpose.TRANSVERSE) out = im.transpose(Transpose.TRANSVERSE)
assert out.mode == mode assert out.mode == mode
@ -124,12 +108,9 @@ def test_tranverse():
assert im.getpixel((1, y - 2)) == out.getpixel((1, x - 2)) assert im.getpixel((1, y - 2)) == out.getpixel((1, x - 2))
assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, 1)) assert im.getpixel((x - 2, y - 2)) == out.getpixel((1, 1))
for mode in HOPPER:
transpose(mode)
@pytest.mark.parametrize("mode", HOPPER)
def test_roundtrip(): def test_roundtrip(mode):
for mode in HOPPER:
im = HOPPER[mode] im = HOPPER[mode]
def transpose(first, second): def transpose(first, second):

View File

@ -625,10 +625,10 @@ def test_polygon2():
helper_polygon(POINTS2) helper_polygon(POINTS2)
def test_polygon_kite(): @pytest.mark.parametrize("mode", ("RGB", "L"))
def test_polygon_kite(mode):
# Test drawing lines of different gradients (dx>dy, dy>dx) and # Test drawing lines of different gradients (dx>dy, dy>dx) and
# vertical (dx==0) and horizontal (dy==0) lines # vertical (dx==0) and horizontal (dy==0) lines
for mode in ["RGB", "L"]:
# Arrange # Arrange
im = Image.new(mode, (W, H)) im = Image.new(mode, (W, H))
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)

View File

@ -16,8 +16,8 @@ if ImageQt.qt_is_installed:
from PIL.ImageQt import QImage from PIL.ImageQt import QImage
def test_sanity(tmp_path): @pytest.mark.parametrize("mode", ("RGB", "RGBA", "L", "P", "1"))
for mode in ("RGB", "RGBA", "L", "P", "1"): def test_sanity(mode, tmp_path):
src = hopper(mode) src = hopper(mode)
data = ImageQt.toqimage(src) data = ImageQt.toqimage(src)
@ -32,12 +32,12 @@ def test_sanity(tmp_path):
assert_image_equal(rt, src) assert_image_equal(rt, src)
if mode == "1": if mode == "1":
# BW appears to not save correctly on QT4 and QT5 # BW appears to not save correctly on QT5
# kicks out errors on console: # kicks out errors on console:
# libpng warning: Invalid color type/bit depth combination # libpng warning: Invalid color type/bit depth combination
# in IHDR # in IHDR
# libpng error: Invalid IHDR data # libpng error: Invalid IHDR data
continue return
# Test saving the file # Test saving the file
tempfile = str(tmp_path / f"temp_{mode}.png") tempfile = str(tmp_path / f"temp_{mode}.png")

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# install libimagequant # install libimagequant
archive=libimagequant-4.0.1 archive=libimagequant-4.0.4
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz

View File

@ -166,7 +166,7 @@ Many of Pillow's features require external libraries:
* **libimagequant** provides improved color quantization * **libimagequant** provides improved color quantization
* Pillow has been tested with libimagequant **2.6-4.0.1** * Pillow has been tested with libimagequant **2.6-4.0.4**
* Libimagequant is licensed GPLv3, which is more restrictive than * Libimagequant is licensed GPLv3, which is more restrictive than
the Pillow license, therefore we will not be distributing binaries the Pillow license, therefore we will not be distributing binaries
with libimagequant support enabled. with libimagequant support enabled.

View File

@ -226,21 +226,21 @@ deps = {
"filename": "lcms2-2.13.1.tar.gz", "filename": "lcms2-2.13.1.tar.gz",
"dir": "lcms2-2.13.1", "dir": "lcms2-2.13.1",
"patch": { "patch": {
r"Projects\VC2019\lcms2_static\lcms2_static.vcxproj": { r"Projects\VC2022\lcms2_static\lcms2_static.vcxproj": {
# default is /MD for x86 and /MT for x64, we need /MD always # default is /MD for x86 and /MT for x64, we need /MD always
"<RuntimeLibrary>MultiThreaded</RuntimeLibrary>": "<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>", # noqa: E501 "<RuntimeLibrary>MultiThreaded</RuntimeLibrary>": "<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>", # noqa: E501
# retarget to default toolset (selected by vcvarsall.bat) # retarget to default toolset (selected by vcvarsall.bat)
"<PlatformToolset>v142</PlatformToolset>": "<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>", # noqa: E501 "<PlatformToolset>v143</PlatformToolset>": "<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>", # noqa: E501
# retarget to latest (selected by vcvarsall.bat) # retarget to latest (selected by vcvarsall.bat)
"<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>": "<WindowsTargetPlatformVersion>$(WindowsSDKVersion)</WindowsTargetPlatformVersion>", # noqa: E501 "<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>": "<WindowsTargetPlatformVersion>$(WindowsSDKVersion)</WindowsTargetPlatformVersion>", # noqa: E501
} }
}, },
"build": [ "build": [
cmd_rmdir("Lib"), cmd_rmdir("Lib"),
cmd_rmdir(r"Projects\VC2019\Release"), cmd_rmdir(r"Projects\VC2022\Release"),
cmd_msbuild(r"Projects\VC2019\lcms2.sln", "Release", "Clean"), cmd_msbuild(r"Projects\VC2022\lcms2.sln", "Release", "Clean"),
cmd_msbuild( cmd_msbuild(
r"Projects\VC2019\lcms2.sln", "Release", "lcms2_static:Rebuild" r"Projects\VC2022\lcms2.sln", "Release", "lcms2_static:Rebuild"
), ),
cmd_xcopy("include", "{inc_dir}"), cmd_xcopy("include", "{inc_dir}"),
], ],