Convert to use pytest

This commit is contained in:
Hugo 2020-02-18 15:50:34 +02:00
parent 17c67a2cfb
commit d289a5b072
4 changed files with 338 additions and 345 deletions

View File

@ -1,114 +1,115 @@
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, assert_image_equal, assert_image_similar, hopper from .helper import assert_image_equal, assert_image_similar, hopper
_webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed")
class TestFileWebpAlpha(PillowTestCase): def setup_module():
def setUp(self): if _webp.WebPDecoderBuggyAlpha():
if _webp.WebPDecoderBuggyAlpha(self): pytest.skip("Buggy early version of WebP installed, not testing transparency")
self.skipTest(
"Buggy early version of WebP installed, not testing transparency"
)
def test_read_rgba(self):
"""
Can we read an RGBA mode file without error?
Does it have the bits we expect?
"""
# Generated with `cwebp transparent.png -o transparent.webp` def test_read_rgba():
file_path = "Tests/images/transparent.webp" """
with Image.open(file_path) as image: Can we read an RGBA mode file without error?
self.assertEqual(image.mode, "RGBA") Does it have the bits we expect?
self.assertEqual(image.size, (200, 150)) """
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
image.tobytes() # Generated with `cwebp transparent.png -o transparent.webp`
file_path = "Tests/images/transparent.webp"
with Image.open(file_path) as image:
assert image.mode == "RGBA"
assert image.size == (200, 150)
assert image.format == "WEBP"
image.load()
image.getdata()
with Image.open("Tests/images/transparent.png") as target: image.tobytes()
assert_image_similar(image, target, 20.0)
def test_write_lossless_rgb(self): with Image.open("Tests/images/transparent.png") as target:
""" assert_image_similar(image, target, 20.0)
Can we write an RGBA mode file with lossless compression without
error? Does it have the bits we expect?
"""
temp_file = self.tempfile("temp.webp")
# temp_file = "temp.webp"
pil_image = hopper("RGBA") def test_write_lossless_rgb(tmp_path):
"""
Can we write an RGBA mode file with lossless compression without error?
Does it have the bits we expect?
"""
mask = Image.new("RGBA", (64, 64), (128, 128, 128, 128)) temp_file = str(tmp_path / "temp.webp")
# Add some partially transparent bits: # temp_file = "temp.webp"
pil_image.paste(mask, (0, 0), mask)
pil_image.save(temp_file, lossless=True) pil_image = hopper("RGBA")
with Image.open(temp_file) as image: mask = Image.new("RGBA", (64, 64), (128, 128, 128, 128))
image.load() # Add some partially transparent bits:
pil_image.paste(mask, (0, 0), mask)
self.assertEqual(image.mode, "RGBA") pil_image.save(temp_file, lossless=True)
self.assertEqual(image.size, pil_image.size)
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
assert_image_equal(image, pil_image) with Image.open(temp_file) as image:
image.load()
def test_write_rgba(self): assert image.mode == "RGBA"
""" assert image.size == pil_image.size
Can we write a RGBA mode file to webp without error. assert image.format == "WEBP"
Does it have the bits we expect? image.load()
""" image.getdata()
temp_file = self.tempfile("temp.webp") assert_image_equal(image, pil_image)
pil_image = Image.new("RGBA", (10, 10), (255, 0, 0, 20))
pil_image.save(temp_file)
if _webp.WebPDecoderBuggyAlpha(self): def test_write_rgba(tmp_path):
return """
Can we write a RGBA mode file to WebP without error.
Does it have the bits we expect?
"""
with Image.open(temp_file) as image: temp_file = str(tmp_path / "temp.webp")
image.load()
self.assertEqual(image.mode, "RGBA") pil_image = Image.new("RGBA", (10, 10), (255, 0, 0, 20))
self.assertEqual(image.size, (10, 10)) pil_image.save(temp_file)
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
# early versions of webp are known to produce higher deviations: if _webp.WebPDecoderBuggyAlpha():
# deal with it return
if _webp.WebPDecoderVersion(self) <= 0x201:
assert_image_similar(image, pil_image, 3.0)
else:
assert_image_similar(image, pil_image, 1.0)
def test_write_unsupported_mode_PA(self): with Image.open(temp_file) as image:
""" image.load()
Saving a palette-based file with transparency to WebP format
should work, and be similar to the original file.
"""
temp_file = self.tempfile("temp.webp") assert image.mode == "RGBA"
file_path = "Tests/images/transparent.gif" assert image.size == (10, 10)
assert image.format == "WEBP"
image.load()
image.getdata()
# Early versions of WebP are known to produce higher deviations:
# deal with it
if _webp.WebPDecoderVersion() <= 0x201:
assert_image_similar(image, pil_image, 3.0)
else:
assert_image_similar(image, pil_image, 1.0)
def test_write_unsupported_mode_PA(tmp_path):
"""
Saving a palette-based file with transparency to WebP format
should work, and be similar to the original file.
"""
temp_file = str(tmp_path / "temp.webp")
file_path = "Tests/images/transparent.gif"
with Image.open(file_path) as im:
im.save(temp_file)
with Image.open(temp_file) as image:
assert image.mode == "RGBA"
assert image.size == (200, 150)
assert image.format == "WEBP"
image.load()
image.getdata()
with Image.open(file_path) as im: with Image.open(file_path) as im:
im.save(temp_file) target = im.convert("RGBA")
with Image.open(temp_file) as image:
self.assertEqual(image.mode, "RGBA")
self.assertEqual(image.size, (200, 150))
self.assertEqual(image.format, "WEBP")
image.load() assert_image_similar(image, target, 25.0)
image.getdata()
with Image.open(file_path) as im:
target = im.convert("RGBA")
assert_image_similar(image, target, 25.0)

View File

@ -1,171 +1,164 @@
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import ( from .helper import assert_image_equal, assert_image_similar, is_big_endian, on_ci
PillowTestCase,
assert_image_equal,
assert_image_similar,
is_big_endian,
on_ci,
)
_webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed")
class TestFileWebpAnimation(PillowTestCase): def setup_module():
def setUp(self): if not _webp.HAVE_WEBPANIM:
if not _webp.HAVE_WEBPANIM: pytest.skip(
self.skipTest( "WebP library does not contain animation support, not testing animation"
"WebP library does not contain animation support, " )
"not testing animation"
def test_n_frames():
"""Ensure that WebP format sets n_frames and is_animated attributes correctly."""
with Image.open("Tests/images/hopper.webp") as im:
assert im.n_frames == 1
assert not im.is_animated
with Image.open("Tests/images/iss634.webp") as im:
assert im.n_frames == 42
assert im.is_animated
@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
def test_write_animation_L(tmp_path):
"""
Convert an animated GIF to animated WebP, then compare the frame count, and first
and last frames to ensure they're visually similar.
"""
with Image.open("Tests/images/iss634.gif") as orig:
assert orig.n_frames > 1
temp_file = str(tmp_path / "temp.webp")
orig.save(temp_file, save_all=True)
with Image.open(temp_file) as im:
assert im.n_frames == orig.n_frames
# Compare first and last frames to the original animated GIF
orig.load()
im.load()
assert_image_similar(im, orig.convert("RGBA"), 25.0)
orig.seek(orig.n_frames - 1)
im.seek(im.n_frames - 1)
orig.load()
im.load()
assert_image_similar(im, orig.convert("RGBA"), 25.0)
@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
def test_write_animation_RGB(tmp_path):
"""
Write an animated WebP from RGB frames, and ensure the frames
are visually similar to the originals.
"""
def check(temp_file):
with Image.open(temp_file) as im:
assert im.n_frames == 2
# Compare first frame to original
im.load()
assert_image_equal(im, frame1.convert("RGBA"))
# Compare second frame to original
im.seek(1)
im.load()
assert_image_equal(im, frame2.convert("RGBA"))
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
temp_file1 = str(tmp_path / "temp.webp")
frame1.copy().save(
temp_file1, save_all=True, append_images=[frame2], lossless=True
)
check(temp_file1)
# Tests appending using a generator
def imGenerator(ims):
yield from ims
temp_file2 = str(tmp_path / "temp_generator.webp")
frame1.copy().save(
temp_file2,
save_all=True,
append_images=imGenerator([frame2]),
lossless=True,
)
check(temp_file2)
def test_timestamp_and_duration(tmp_path):
"""
Try passing a list of durations, and make sure the encoded
timestamps and durations are correct.
"""
durations = [0, 10, 20, 30, 40]
temp_file = str(tmp_path / "temp.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2, frame1],
duration=durations,
) )
def test_n_frames(self): with Image.open(temp_file) as im:
""" assert im.n_frames == 5
Ensure that WebP format sets n_frames and is_animated assert im.is_animated
attributes correctly.
"""
with Image.open("Tests/images/hopper.webp") as im: # Check that timestamps and durations match original values specified
self.assertEqual(im.n_frames, 1) ts = 0
self.assertFalse(im.is_animated) for frame in range(im.n_frames):
im.seek(frame)
im.load()
assert im.info["duration"] == durations[frame]
assert im.info["timestamp"] == ts
ts += durations[frame]
with Image.open("Tests/images/iss634.webp") as im:
self.assertEqual(im.n_frames, 42)
self.assertTrue(im.is_animated)
@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian") def test_seeking(tmp_path):
def test_write_animation_L(self): """
""" Create an animated WebP file, and then try seeking through frames in reverse-order,
Convert an animated GIF to animated WebP, then compare the verifying the timestamps and durations are correct.
frame count, and first and last frames to ensure they're """
visually similar.
"""
with Image.open("Tests/images/iss634.gif") as orig: dur = 33
self.assertGreater(orig.n_frames, 1) temp_file = str(tmp_path / "temp.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2, frame1],
duration=dur,
)
temp_file = self.tempfile("temp.webp") with Image.open(temp_file) as im:
orig.save(temp_file, save_all=True) assert im.n_frames == 5
with Image.open(temp_file) as im: assert im.is_animated
self.assertEqual(im.n_frames, orig.n_frames)
# Compare first and last frames to the original animated GIF # Traverse frames in reverse, checking timestamps and durations
orig.load() ts = dur * (im.n_frames - 1)
im.load() for frame in reversed(range(im.n_frames)):
assert_image_similar(im, orig.convert("RGBA"), 25.0) im.seek(frame)
orig.seek(orig.n_frames - 1) im.load()
im.seek(im.n_frames - 1) assert im.info["duration"] == dur
orig.load() assert im.info["timestamp"] == ts
im.load() ts -= dur
assert_image_similar(im, orig.convert("RGBA"), 25.0)
@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian")
def test_write_animation_RGB(self):
"""
Write an animated WebP from RGB frames, and ensure the frames
are visually similar to the originals.
"""
def check(temp_file): def test_seek_errors():
with Image.open(temp_file) as im: with Image.open("Tests/images/iss634.webp") as im:
self.assertEqual(im.n_frames, 2) with pytest.raises(EOFError):
im.seek(-1)
# Compare first frame to original with pytest.raises(EOFError):
im.load() im.seek(42)
assert_image_equal(im, frame1.convert("RGBA"))
# Compare second frame to original
im.seek(1)
im.load()
assert_image_equal(im, frame2.convert("RGBA"))
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
temp_file1 = self.tempfile("temp.webp")
frame1.copy().save(
temp_file1, save_all=True, append_images=[frame2], lossless=True
)
check(temp_file1)
# Tests appending using a generator
def imGenerator(ims):
yield from ims
temp_file2 = self.tempfile("temp_generator.webp")
frame1.copy().save(
temp_file2,
save_all=True,
append_images=imGenerator([frame2]),
lossless=True,
)
check(temp_file2)
def test_timestamp_and_duration(self):
"""
Try passing a list of durations, and make sure the encoded
timestamps and durations are correct.
"""
durations = [0, 10, 20, 30, 40]
temp_file = self.tempfile("temp.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2, frame1],
duration=durations,
)
with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, 5)
self.assertTrue(im.is_animated)
# Check that timestamps and durations match original values specified
ts = 0
for frame in range(im.n_frames):
im.seek(frame)
im.load()
self.assertEqual(im.info["duration"], durations[frame])
self.assertEqual(im.info["timestamp"], ts)
ts += durations[frame]
def test_seeking(self):
"""
Create an animated WebP file, and then try seeking through
frames in reverse-order, verifying the timestamps and durations
are correct.
"""
dur = 33
temp_file = self.tempfile("temp.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2, frame1],
duration=dur,
)
with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, 5)
self.assertTrue(im.is_animated)
# Traverse frames in reverse, checking timestamps and durations
ts = dur * (im.n_frames - 1)
for frame in reversed(range(im.n_frames)):
im.seek(frame)
im.load()
self.assertEqual(im.info["duration"], dur)
self.assertEqual(im.info["timestamp"], ts)
ts -= dur
def test_seek_errors(self):
with Image.open("Tests/images/iss634.webp") as im:
with self.assertRaises(EOFError):
im.seek(-1)
with self.assertRaises(EOFError):
im.seek(42)

View File

@ -1,30 +1,28 @@
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase, assert_image_equal, hopper from .helper import assert_image_equal, hopper
_webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed")
RGB_MODE = "RGB"
class TestFileWebpLossless(PillowTestCase):
def setUp(self):
if _webp.WebPDecoderVersion() < 0x0200:
self.skipTest("lossless not included")
self.rgb_mode = "RGB" def test_write_lossless_rgb(tmp_path):
if _webp.WebPDecoderVersion() < 0x0200:
pytest.skip("lossless not included")
def test_write_lossless_rgb(self): temp_file = str(tmp_path / "temp.webp")
temp_file = self.tempfile("temp.webp")
hopper(self.rgb_mode).save(temp_file, lossless=True) hopper(RGB_MODE).save(temp_file, lossless=True)
with Image.open(temp_file) as image: with Image.open(temp_file) as image:
image.load() image.load()
self.assertEqual(image.mode, self.rgb_mode) assert image.mode == RGB_MODE
self.assertEqual(image.size, (128, 128)) assert image.size == (128, 128)
self.assertEqual(image.format, "WEBP") assert image.format == "WEBP"
image.load() image.load()
image.getdata() image.getdata()
assert_image_equal(image, hopper(self.rgb_mode)) assert_image_equal(image, hopper(RGB_MODE))

View File

@ -3,119 +3,120 @@ from io import BytesIO
import pytest import pytest
from PIL import Image from PIL import Image
from .helper import PillowTestCase
_webp = pytest.importorskip("PIL._webp", reason="WebP support not installed") _webp = pytest.importorskip("PIL._webp", reason="WebP support not installed")
class TestFileWebpMetadata(PillowTestCase): def setup_module():
def setUp(self): if not _webp.HAVE_WEBPMUX:
if not _webp.HAVE_WEBPMUX: pytest.skip("WebPMux support not installed")
self.skipTest("WebPMux support not installed")
def test_read_exif_metadata(self):
file_path = "Tests/images/flower.webp" def test_read_exif_metadata():
with Image.open(file_path) as image:
self.assertEqual(image.format, "WEBP") file_path = "Tests/images/flower.webp"
exif_data = image.info.get("exif", None) with Image.open(file_path) as image:
self.assertTrue(exif_data)
exif = image._getexif() assert image.format == "WEBP"
exif_data = image.info.get("exif", None)
assert exif_data
# camera make exif = image._getexif()
self.assertEqual(exif[271], "Canon")
with Image.open("Tests/images/flower.jpg") as jpeg_image: # Camera make
expected_exif = jpeg_image.info["exif"] assert exif[271] == "Canon"
self.assertEqual(exif_data, expected_exif) with Image.open("Tests/images/flower.jpg") as jpeg_image:
expected_exif = jpeg_image.info["exif"]
def test_write_exif_metadata(self): assert exif_data == expected_exif
file_path = "Tests/images/flower.jpg"
test_buffer = BytesIO()
with Image.open(file_path) as image:
expected_exif = image.info["exif"]
image.save(test_buffer, "webp", exif=expected_exif)
test_buffer.seek(0) def test_write_exif_metadata():
with Image.open(test_buffer) as webp_image: file_path = "Tests/images/flower.jpg"
webp_exif = webp_image.info.get("exif", None) test_buffer = BytesIO()
self.assertTrue(webp_exif) with Image.open(file_path) as image:
if webp_exif: expected_exif = image.info["exif"]
self.assertEqual(webp_exif, expected_exif, "WebP EXIF didn't match")
def test_read_icc_profile(self): image.save(test_buffer, "webp", exif=expected_exif)
file_path = "Tests/images/flower2.webp" test_buffer.seek(0)
with Image.open(file_path) as image: with Image.open(test_buffer) as webp_image:
webp_exif = webp_image.info.get("exif", None)
assert webp_exif
if webp_exif:
assert webp_exif == expected_exif, "WebP EXIF didn't match"
self.assertEqual(image.format, "WEBP")
self.assertTrue(image.info.get("icc_profile", None))
icc = image.info["icc_profile"] def test_read_icc_profile():
with Image.open("Tests/images/flower2.jpg") as jpeg_image: file_path = "Tests/images/flower2.webp"
expected_icc = jpeg_image.info["icc_profile"] with Image.open(file_path) as image:
self.assertEqual(icc, expected_icc) assert image.format == "WEBP"
assert image.info.get("icc_profile", None)
def test_write_icc_metadata(self): icc = image.info["icc_profile"]
file_path = "Tests/images/flower2.jpg"
test_buffer = BytesIO()
with Image.open(file_path) as image:
expected_icc_profile = image.info["icc_profile"]
image.save(test_buffer, "webp", icc_profile=expected_icc_profile) with Image.open("Tests/images/flower2.jpg") as jpeg_image:
expected_icc = jpeg_image.info["icc_profile"]
test_buffer.seek(0) assert icc == expected_icc
with Image.open(test_buffer) as webp_image:
webp_icc_profile = webp_image.info.get("icc_profile", None)
self.assertTrue(webp_icc_profile)
if webp_icc_profile: def test_write_icc_metadata():
self.assertEqual( file_path = "Tests/images/flower2.jpg"
webp_icc_profile, expected_icc_profile, "Webp ICC didn't match" test_buffer = BytesIO()
with Image.open(file_path) as image:
expected_icc_profile = image.info["icc_profile"]
image.save(test_buffer, "webp", icc_profile=expected_icc_profile)
test_buffer.seek(0)
with Image.open(test_buffer) as webp_image:
webp_icc_profile = webp_image.info.get("icc_profile", None)
assert webp_icc_profile
if webp_icc_profile:
assert webp_icc_profile == expected_icc_profile, "Webp ICC didn't match"
def test_read_no_exif():
file_path = "Tests/images/flower.jpg"
test_buffer = BytesIO()
with Image.open(file_path) as image:
assert "exif" in image.info
image.save(test_buffer, "webp")
test_buffer.seek(0)
with Image.open(test_buffer) as webp_image:
assert not webp_image._getexif()
def test_write_animated_metadata(tmp_path):
if not _webp.HAVE_WEBPANIM:
pytest.skip("WebP animation support not available")
iccp_data = b"<iccp_data>"
exif_data = b"<exif_data>"
xmp_data = b"<xmp_data>"
temp_file = str(tmp_path / "temp.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2],
icc_profile=iccp_data,
exif=exif_data,
xmp=xmp_data,
) )
def test_read_no_exif(self): with Image.open(temp_file) as image:
file_path = "Tests/images/flower.jpg" assert "icc_profile" in image.info
test_buffer = BytesIO() assert "exif" in image.info
with Image.open(file_path) as image: assert "xmp" in image.info
self.assertIn("exif", image.info) assert iccp_data == image.info.get("icc_profile", None)
assert exif_data == image.info.get("exif", None)
image.save(test_buffer, "webp") assert xmp_data == image.info.get("xmp", None)
test_buffer.seek(0)
with Image.open(test_buffer) as webp_image:
self.assertFalse(webp_image._getexif())
def test_write_animated_metadata(self):
if not _webp.HAVE_WEBPANIM:
self.skipTest("WebP animation support not available")
iccp_data = b"<iccp_data>"
exif_data = b"<exif_data>"
xmp_data = b"<xmp_data>"
temp_file = self.tempfile("temp.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2],
icc_profile=iccp_data,
exif=exif_data,
xmp=xmp_data,
)
with Image.open(temp_file) as image:
self.assertIn("icc_profile", image.info)
self.assertIn("exif", image.info)
self.assertIn("xmp", image.info)
self.assertEqual(iccp_data, image.info.get("icc_profile", None))
self.assertEqual(exif_data, image.info.get("exif", None))
self.assertEqual(xmp_data, image.info.get("xmp", None))