File: test_file_webp_animated.py

package info (click to toggle)
pillow 8.1.2%2Bdfsg-0.3%2Bdeb11u2
  • links: PTS
  • area: main
  • in suites: bullseye
  • size: 65,628 kB
  • sloc: python: 35,630; ansic: 31,009; makefile: 388; javascript: 114; sh: 77
file content (166 lines) | stat: -rw-r--r-- 5,067 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import pytest

from PIL import Image

from .helper import (
    assert_image_equal,
    assert_image_similar,
    is_big_endian,
    skip_unless_feature,
)

pytestmark = [
    skip_unless_feature("webp"),
    skip_unless_feature("webp_anim"),
]


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(), 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(), 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,
            )

    with Image.open(temp_file) as im:
        assert im.n_frames == 5
        assert 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()
            assert im.info["duration"] == durations[frame]
            assert im.info["timestamp"] == ts
            ts += durations[frame]


def test_seeking(tmp_path):
    """
    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 = 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,
            )

    with Image.open(temp_file) as im:
        assert im.n_frames == 5
        assert 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()
            assert im.info["duration"] == dur
            assert im.info["timestamp"] == ts
            ts -= dur


def test_seek_errors():
    with Image.open("Tests/images/iss634.webp") as im:
        with pytest.raises(EOFError):
            im.seek(-1)

        with pytest.raises(EOFError):
            im.seek(42)