From d21bf6cb711124fe28c10f8c96173c228ae5dc8e Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 8 Jan 2026 10:26:22 -0800
Subject: [PATCH] IMG_webp: Fix animated WebP frame composition (thanks
@inigomonyota!)
Combines disposal and blend preparation into a single operation
- Properly handles WEBP_MUX_DISPOSE_BACKGROUND with alpha channel status
- Correctly applies bgcolor for non-alpha WebPs and transparency for alpha WebPs
- Sets appropriate blend modes (BLEND/NONE) based on frame's blend_method
Closes https://github.com/libsdl-org/SDL_image/pull/522
---
src/IMG_webp.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/src/IMG_webp.c b/src/IMG_webp.c
index f54baf1e2..9b55bca2b 100644
--- a/src/IMG_webp.c
+++ b/src/IMG_webp.c
@@ -355,6 +355,13 @@ IMG_Animation *IMG_LoadWEBPAnimation_RW(SDL_RWops *src)
(bgcolor >> 24) & 0xFF);
#endif
+ /* Initialize canvas - use bgcolor for non-alpha format, transparency for alpha */
+ if (features.has_alpha) {
+ SDL_FillRect(canvas, NULL, SDL_MapRGBA(canvas->format, 0, 0, 0, 0));
+ } else {
+ SDL_FillRect(canvas, NULL, bgcolor);
+ }
+
SDL_zero(iter);
if (lib.WebPDemuxGetFrame(demuxer, 1, &iter)) {
do {
@@ -365,8 +372,16 @@ IMG_Animation *IMG_LoadWEBPAnimation_RW(SDL_RWops *src)
continue;
}
- if (dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
- SDL_FillRect(canvas, NULL, bgcolor);
+ /* Set up destination rect for current frame */
+ dst.x = iter.x_offset;
+ dst.y = iter.y_offset;
+ dst.w = iter.width;
+ dst.h = iter.height;
+
+ /* Handle disposal and prepare region for new frame */
+ if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ||
+ iter.blend_method == WEBP_MUX_NO_BLEND) {
+ SDL_FillRect(canvas, &dst, bgcolor);
}
curr = SDL_CreateRGBSurfaceWithFormat(0, iter.width, iter.height, 0, SDL_PIXELFORMAT_RGBA32);
@@ -384,21 +399,19 @@ IMG_Animation *IMG_LoadWEBPAnimation_RW(SDL_RWops *src)
goto error;
}
+ /* Set blend mode based on the frame's blend method */
if (iter.blend_method == WEBP_MUX_BLEND) {
SDL_SetSurfaceBlendMode(curr, SDL_BLENDMODE_BLEND);
} else {
SDL_SetSurfaceBlendMode(curr, SDL_BLENDMODE_NONE);
}
- dst.x = iter.x_offset;
- dst.y = iter.y_offset;
- dst.w = iter.width;
- dst.h = iter.height;
+
SDL_BlitSurface(curr, NULL, canvas, &dst);
SDL_FreeSurface(curr);
+ /* Store complete frame state */
anim->frames[frame_idx] = SDL_DuplicateSurface(canvas);
anim->delays[frame_idx] = iter.duration;
- dispose_method = iter.dispose_method;
} while (lib.WebPDemuxNextFrame(&iter));