mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 18:06:18 +03:00
167 lines
5.7 KiB
Python
167 lines
5.7 KiB
Python
import pytest
|
|
from PIL import Image
|
|
|
|
from .helper import PillowTestCase, is_big_endian, on_ci
|
|
|
|
try:
|
|
from PIL import _webp
|
|
|
|
HAVE_WEBP = True
|
|
except ImportError:
|
|
HAVE_WEBP = False
|
|
|
|
|
|
class TestFileWebpAnimation(PillowTestCase):
|
|
def setUp(self):
|
|
if not HAVE_WEBP:
|
|
self.skipTest("WebP support not installed")
|
|
return
|
|
|
|
if not _webp.HAVE_WEBPANIM:
|
|
self.skipTest(
|
|
"WebP library does not contain animation support, "
|
|
"not testing animation"
|
|
)
|
|
|
|
def test_n_frames(self):
|
|
"""
|
|
Ensure that WebP format sets n_frames and is_animated
|
|
attributes correctly.
|
|
"""
|
|
|
|
with Image.open("Tests/images/hopper.webp") as im:
|
|
self.assertEqual(im.n_frames, 1)
|
|
self.assertFalse(im.is_animated)
|
|
|
|
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_write_animation_L(self):
|
|
"""
|
|
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:
|
|
self.assertGreater(orig.n_frames, 1)
|
|
|
|
temp_file = self.tempfile("temp.webp")
|
|
orig.save(temp_file, save_all=True)
|
|
with Image.open(temp_file) as im:
|
|
self.assertEqual(im.n_frames, orig.n_frames)
|
|
|
|
# Compare first and last frames to the original animated GIF
|
|
orig.load()
|
|
im.load()
|
|
self.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()
|
|
self.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):
|
|
with Image.open(temp_file) as im:
|
|
self.assertEqual(im.n_frames, 2)
|
|
|
|
# Compare first frame to original
|
|
im.load()
|
|
self.assert_image_equal(im, frame1.convert("RGBA"))
|
|
|
|
# Compare second frame to original
|
|
im.seek(1)
|
|
im.load()
|
|
self.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
|