[Bug] An animated WebP source is flattened to one frame at decode, while an animated GIF survives
Thumbor Request URL
http://example.com/unsafe/50x0/animated.webp
Expected Behaviour
Either the animation survives, the way it does for an animated GIF, or the request fails so the caller knows the animation was dropped.
Actual Behaviour
The animated WebP comes back as a single frame with a 200, so a caller cannot tell anything was lost.
It happens at decode rather than in any transform: even an untouched delivery is already one frame. There is no animated WebP in tests/fixtures/images, so the repro generates one, with an animated GIF built the same way as the control:
from PIL import Image
frames = [Image.new("RGB", (100, 100), c) for c in ((255,0,0), (0,0,255), (0,255,0))]
frames[0].save("animated.webp", save_all=True, append_images=frames[1:], duration=200, loop=0)
frames[0].save("animated.gif", save_all=True, append_images=frames[1:], duration=200, loop=0)Both sources are 100x100 with 3 frames. Through thumbor 7.7.7:
animated.webp untouched -> WEBP 100x100 1 frame
animated.webp 50x0 -> WEBP 50x50 1 frame
animated.webp filters:grayscale() -> WEBP 100x100 1 frame
animated.gif untouched (control) -> GIF 100x100 3 frames
animated.gif 50x0 (control) -> GIF 50x50 3 framesThe GIF arm is the control, so this is not a build without animation support. The grayscale() row shows the filter phase runs fine on the WebP, it is only the frames that are gone.
PILEngine.create_image() builds a frame list only when the extension is .gif, everything else returns a single image, which would put animated AVIF and APNG in the same position. I have not measured those.
I am not asking for animated WebP support as such, and I realise #583 covered the output side years ago. The part that is awkward from a client's point of view is that there is no signal. Erroring, or documenting that GIF is the only animated input container, would be enough.
Operating System
Official Docker image ghcr.io/thumbor/thumbor:latest (Debian 11 bullseye, thumbor 7.7.7, Pillow 10.4.0), host macOS 15.7.3.
Your thumbor.conf
SECURITY_KEY = "dummy-key"
ALLOW_UNSAFE_URL = True
LOADER = "thumbor.loaders.http_loader"
# nothing else set, ALLOW_ANIMATED_GIFS left at its True defaultSource: thumbor/thumbor