Skip to content

Animated webp does not populate info dictionary on seek #9790

Description

@qazmlpok

What did you do?

Loaded an animated webp to display it as an animation

What did you expect to happen?

'duration' data should be populated within the image on load, and refreshed when seeking to another file. This is what happens with an animated gif.

What actually happened?

'duration' data in the info struct is not populated until the current frame is consumed by calling convert('RGB'). Other methods can probably trigger this; I didn't investigate into what exactly loads info. For animated gifs and APNG, the info struct is populated immediately on seek().

What are your OS, Python and Pillow versions?

  • OS: Ubuntu 24.04.4 LTS (also tested on Windows 10)
  • Python: Python 3.12.3
  • Pillow: 12.3.0
--------------------------------------------------------------------
Pillow 12.1.1
Python 3.12.3 (main, Jun 19 2026, 12:46:00) [GCC 13.3.0]
--------------------------------------------------------------------
Python executable is /home/qaz/python-venv/bin/python3
Environment Python files loaded from /home/qaz/python-venv
System Python files loaded from /usr
--------------------------------------------------------------------
Python Pillow modules loaded from /home/qaz/python-venv/lib/python3.12/site-packages/PIL
Binary Pillow modules loaded from /home/qaz/python-venv/lib/python3.12/site-packages/PIL
--------------------------------------------------------------------
--- PIL CORE support ok, compiled for 12.1.1
*** TKINTER support not installed
--- FREETYPE2 support ok, loaded 2.14.1
--- LITTLECMS2 support ok, loaded 2.17
--- WEBP support ok, loaded 1.6.0
--- AVIF support ok, loaded 1.3.0
--- JPEG support ok, compiled for libjpeg-turbo 3.1.3
--- OPENJPEG (JPEG2000) support ok, loaded 2.5.4
--- ZLIB (PNG/ZIP) support ok, loaded 1.3, compiled for zlib-ng 2.3.2
--- LIBTIFF support ok, loaded 4.7.1
--- RAQM (Bidirectional Text) support ok, loaded 0.10.3, fribidi 1.0.13, harfbuzz 12.3.0
*** LIBIMAGEQUANT (Quantization method) support not installed
--- XCB (X protocol) support ok
--------------------------------------------------------------------

import os, sys
import io
from PIL import Image

filenames = ['clock.gif', 'clock.webp']

for fname in filenames:
    print("Open:", fname)
    img = Image.open(fname)
    is_animated = getattr(img, "is_animated", False)
    count = img.n_frames
    delays = [None] * count
    for i in range(count):
        img.seek(i) 
        print(i, "img info is", img.info)  # --for the gif, the img.info includes 'duration'
        delays[i] = img.info.get('duration', '-')
        frame = img.convert('RGB')
        print(i, "img info is now", img.info)   # --This loads the first frame for WEBP
    print(f'Animated? {is_animated}. Frames: {count}. Delays[0]: {delays[0]}. Delays[1]: {delays[1]}. Delays[5]: {delays[5]}')
    print("Finished with", fname, "\n")
    img.close()

'clock.gif' and 'clock.webp' are just animated images I generated for testing.

https://github.com/user-attachments/assets/38429bab-ceeb-40aa-8026-35a68b79dd2a"
https://github.com/user-attachments/assets/1bf95ff8-3865-4292-959a-7ffa6d0963e0"

Sample relevant output:

Gif:

Open: clock.gif
0 img info is {'version': b'GIF89a', 'background': 0, 'loop': 0, 'duration': 1000, 'extension': (b'NETSCAPE2.0', 795)}
0 img info is now {'version': b'GIF89a', 'background': 0, 'loop': 0, 'duration': 1000, 'extension': (b'NETSCAPE2.0', 795)}
1 img info is {'version': b'GIF89a', 'background': 0, 'loop': 0, 'duration': 1000}
1 img info is now {'version': b'GIF89a', 'background': 0, 'loop': 0, 'duration': 1000}
...
5 img info is {'version': b'GIF89a', 'background': 0, 'loop': 0, 'duration': 5000}
5 img info is now {'version': b'GIF89a', 'background': 0, 'loop': 0, 'duration': 5000}

Webp:

Open: clock.webp
0 img info is {'loop': 0, 'background': (0, 0, 0, 0)}
0 img info is now {'loop': 0, 'background': (0, 0, 0, 0), 'timestamp': 0, 'duration': 1000}
1 img info is {'loop': 0, 'background': (0, 0, 0, 0), 'timestamp': 0, 'duration': 1000}
1 img info is now {'loop': 0, 'background': (0, 0, 0, 0), 'timestamp': 1000, 'duration': 1000}
...
5 img info is {'loop': 0, 'background': (0, 0, 0, 0), 'timestamp': 4000, 'duration': 1000}
5 img info is now {'loop': 0, 'background': (0, 0, 0, 0), 'timestamp': 5000, 'duration': 5000}

For the GIF, the duration is immediately available after seeking. For the webp, seeking does not update/populate duration, so it is showing the previous frame's data (or nothing at all for the first frame) until img.convert('RGB') is called.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions