From 4686d9d5dfdfaadf967d731c71521583b6d8d6f0 Mon Sep 17 00:00:00 2001
From: Xen <[EMAIL REDACTED]>
Date: Tue, 29 Jul 2025 01:50:10 +0300
Subject: [PATCH] Update IMG_webp.c (#572)
Fix API inconsistency with allowing animated WebP images to be used with IMG_LoadWEBP_IO to extract a single frame, just like GIF.
(cherry picked from commit 56f15a087357f96bd2dca8f64e4cc628b3cb5c21)
---
src/IMG_webp.c | 55 +++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 46 insertions(+), 9 deletions(-)
diff --git a/src/IMG_webp.c b/src/IMG_webp.c
index 71b1d0e40..4bc13af02 100644
--- a/src/IMG_webp.c
+++ b/src/IMG_webp.c
@@ -166,6 +166,8 @@ bool IMG_isWEBP(SDL_IOStream *src)
return webp_getinfo(src, NULL);
}
+static IMG_Animation *IMG_LoadWEBPAnimation_IO_Internal(SDL_IOStream *src, int maxFrames);
+
SDL_Surface *IMG_LoadWEBP_IO(SDL_IOStream *src)
{
Sint64 start;
@@ -194,7 +196,7 @@ SDL_Surface *IMG_LoadWEBP_IO(SDL_IOStream *src)
goto error;
}
- raw_data = (uint8_t*) SDL_malloc(raw_data_size);
+ raw_data = (uint8_t *)SDL_malloc(raw_data_size);
if (raw_data == NULL) {
error = "Failed to allocate enough buffer for WEBP";
goto error;
@@ -219,10 +221,39 @@ SDL_Surface *IMG_LoadWEBP_IO(SDL_IOStream *src)
goto error;
}
+ // Special casing for animated WebP images to extract a single frame.
+ if (features.has_animation) {
+ if (SDL_SeekIO(src, start, SDL_IO_SEEK_SET) < 0) {
+ error = "Failed to seek IO to read animated WebP";
+ goto error;
+ } else {
+ IMG_Animation *animation = IMG_LoadWEBPAnimation_IO_Internal(src, 1);
+ if (animation && animation->count > 0) {
+ SDL_Surface *surf = animation->frames[0];
+ if (surf) {
+ ++surf->refcount;
+ if (raw_data) {
+ SDL_free(raw_data);
+ }
+ IMG_FreeAnimation(animation);
+ return surf;
+ } else {
+ error = "Failed to load first frame of animated WebP";
+ IMG_FreeAnimation(animation);
+ goto error;
+ }
+ } else {
+ IMG_FreeAnimation(animation);
+ error = "Received an animated WebP but the animation data was invalid";
+ goto error;
+ }
+ }
+ }
+
if (features.has_alpha) {
- format = SDL_PIXELFORMAT_RGBA32;
+ format = SDL_PIXELFORMAT_RGBA32;
} else {
- format = SDL_PIXELFORMAT_RGB24;
+ format = SDL_PIXELFORMAT_RGB24;
}
surface = SDL_CreateSurface(features.width, features.height, format);
@@ -232,9 +263,9 @@ SDL_Surface *IMG_LoadWEBP_IO(SDL_IOStream *src)
}
if (features.has_alpha) {
- ret = lib.WebPDecodeRGBAInto(raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h, surface->pitch);
+ ret = lib.WebPDecodeRGBAInto(raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h, surface->pitch);
} else {
- ret = lib.WebPDecodeRGBInto(raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h, surface->pitch);
+ ret = lib.WebPDecodeRGBInto(raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h, surface->pitch);
}
if (!ret) {
@@ -248,7 +279,6 @@ SDL_Surface *IMG_LoadWEBP_IO(SDL_IOStream *src)
return surface;
-
error:
if (raw_data) {
SDL_free(raw_data);
@@ -266,7 +296,7 @@ SDL_Surface *IMG_LoadWEBP_IO(SDL_IOStream *src)
return NULL;
}
-IMG_Animation *IMG_LoadWEBPAnimation_IO(SDL_IOStream *src)
+static IMG_Animation *IMG_LoadWEBPAnimation_IO_Internal(SDL_IOStream *src, int maxFrames)
{
Sint64 start;
const char *error = NULL;
@@ -298,7 +328,7 @@ IMG_Animation *IMG_LoadWEBPAnimation_IO(SDL_IOStream *src)
goto error;
}
- raw_data = (uint8_t*) SDL_malloc(raw_data_size);
+ raw_data = (uint8_t *)SDL_malloc(raw_data_size);
if (raw_data == NULL) {
goto error;
}
@@ -326,7 +356,8 @@ IMG_Animation *IMG_LoadWEBPAnimation_IO(SDL_IOStream *src)
}
anim->w = features.width;
anim->h = features.height;
- anim->count = lib.WebPDemuxGetI(demuxer, WEBP_FF_FRAME_COUNT);
+ uint32_t fc = lib.WebPDemuxGetI(demuxer, WEBP_FF_FRAME_COUNT);
+ anim->count = maxFrames > 0 ? SDL_min((unsigned)maxFrames, fc) : fc;
anim->frames = (SDL_Surface **)SDL_calloc(anim->count, sizeof(*anim->frames));
anim->delays = (int *)SDL_calloc(anim->count, sizeof(*anim->delays));
if (!anim->frames || !anim->delays) {
@@ -355,6 +386,7 @@ IMG_Animation *IMG_LoadWEBPAnimation_IO(SDL_IOStream *src)
#endif
SDL_zero(iter);
+
if (lib.WebPDemuxGetFrame(demuxer, 1, &iter)) {
do {
int frame_idx = (iter.frame_num - 1);
@@ -428,6 +460,11 @@ IMG_Animation *IMG_LoadWEBPAnimation_IO(SDL_IOStream *src)
return NULL;
}
+IMG_Animation *IMG_LoadWEBPAnimation_IO(SDL_IOStream *src)
+{
+ return IMG_LoadWEBPAnimation_IO_Internal(src, 0);
+}
+
#else
#if defined(_MSC_VER) && _MSC_VER >= 1300
#pragma warning(disable : 4100) /* warning C4100: 'op' : unreferenced formal parameter */