-
Notifications
You must be signed in to change notification settings - Fork 233
IMG_webp: Incorrect frame composition in animated WebP loading #522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: SDL2
Are you sure you want to change the base?
Changes from 2 commits
7ace470
09b4899
374730d
2638cb2
312ae53
b105e30
a27e2ed
387b5d5
8f6c6a0
abeb7bf
f8d4896
ed1bda3
b8c0093
bfbbc2c
609cd35
683d653
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -259,7 +259,7 @@ SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src) | |||||
return NULL; | ||||||
} | ||||||
|
||||||
IMG_Animation *IMG_LoadWEBPAnimation_RW(SDL_RWops *src) | ||||||
IMG_Animation* IMG_LoadWEBPAnimation_RW(SDL_RWops *src) | ||||||
{ | ||||||
Sint64 start; | ||||||
const char *error = NULL; | ||||||
|
@@ -272,7 +272,8 @@ IMG_Animation *IMG_LoadWEBPAnimation_RW(SDL_RWops *src) | |||||
WebPData wd; | ||||||
uint32_t bgcolor; | ||||||
SDL_Surface *canvas = NULL; | ||||||
WebPMuxAnimDispose dispose_method = WEBP_MUX_DISPOSE_BACKGROUND; | ||||||
SDL_Surface *prevCanvas = NULL; | ||||||
SDL_Rect prevRect = { 0 }; | ||||||
|
||||||
if (!src) { | ||||||
/* The error message has been set in SDL_RWFromFile */ | ||||||
|
@@ -313,7 +314,7 @@ IMG_Animation *IMG_LoadWEBPAnimation_RW(SDL_RWops *src) | |||||
goto error; | ||||||
} | ||||||
|
||||||
anim = (IMG_Animation *)SDL_calloc(1, sizeof(*anim)); | ||||||
anim = (IMG_Animation*)SDL_calloc(1, sizeof(*anim)); | ||||||
if (!anim) { | ||||||
goto error; | ||||||
} | ||||||
|
@@ -327,27 +328,39 @@ IMG_Animation *IMG_LoadWEBPAnimation_RW(SDL_RWops *src) | |||||
} | ||||||
|
||||||
canvas = SDL_CreateRGBSurfaceWithFormat(0, anim->w, anim->h, 0, features.has_alpha ? SDL_PIXELFORMAT_RGBA32 : SDL_PIXELFORMAT_RGBX32); | ||||||
if (!canvas) { | ||||||
prevCanvas = SDL_CreateRGBSurfaceWithFormat(0, anim->w, anim->h, 0, features.has_alpha ? SDL_PIXELFORMAT_RGBA32 : SDL_PIXELFORMAT_RGBX32); | ||||||
if (!canvas || !prevCanvas) { | ||||||
goto error; | ||||||
} | ||||||
|
||||||
/* Background color is BGRA byte order according to the spec */ | ||||||
bgcolor = lib.WebPDemuxGetI(demuxer, WEBP_FF_BACKGROUND_COLOR); | ||||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN | ||||||
bgcolor = SDL_MapRGBA(canvas->format, | ||||||
(bgcolor >> 8) & 0xFF, | ||||||
(bgcolor >> 16) & 0xFF, | ||||||
(bgcolor >> 24) & 0xFF, | ||||||
(bgcolor >> 0) & 0xFF); | ||||||
(bgcolor >> 8) & 0xFF, | ||||||
(bgcolor >> 16) & 0xFF, | ||||||
(bgcolor >> 24) & 0xFF, | ||||||
(bgcolor >> 0) & 0xFF); | ||||||
#else | ||||||
bgcolor = SDL_MapRGBA(canvas->format, | ||||||
(bgcolor >> 16) & 0xFF, | ||||||
(bgcolor >> 8) & 0xFF, | ||||||
(bgcolor >> 0) & 0xFF, | ||||||
(bgcolor >> 24) & 0xFF); | ||||||
(bgcolor >> 16) & 0xFF, | ||||||
(bgcolor >> 8) & 0xFF, | ||||||
(bgcolor >> 0) & 0xFF, | ||||||
(bgcolor >> 24) & 0xFF); | ||||||
#endif | ||||||
|
||||||
// Initialize both canvases - 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)); | ||||||
SDL_FillRect(prevCanvas, NULL, SDL_MapRGBA(prevCanvas->format, 0, 0, 0, 0)); | ||||||
} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. got it |
||||||
else { | ||||||
SDL_FillRect(canvas, NULL, bgcolor); | ||||||
SDL_FillRect(prevCanvas, NULL, bgcolor); | ||||||
} | ||||||
|
||||||
SDL_zero(iter); | ||||||
WebPMuxAnimDispose dispose_method = WEBP_MUX_DISPOSE_BACKGROUND; | ||||||
if (lib.WebPDemuxGetFrame(demuxer, 1, &iter)) { | ||||||
do { | ||||||
SDL_Surface* curr; | ||||||
|
@@ -357,8 +370,15 @@ 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 of THIS frame's region before drawing it | ||||||
if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { | ||||||
SDL_FillRect(canvas, &dst, SDL_MapRGBA(canvas->format, 0, 0, 0, 0)); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. disposing with the background should use the background color, not black. |
||||||
} | ||||||
|
||||||
curr = SDL_CreateRGBSurfaceWithFormat(0, iter.width, iter.height, 0, SDL_PIXELFORMAT_RGBA32); | ||||||
|
@@ -367,65 +387,73 @@ IMG_Animation *IMG_LoadWEBPAnimation_RW(SDL_RWops *src) | |||||
} | ||||||
|
||||||
if (!lib.WebPDecodeRGBAInto(iter.fragment.bytes, | ||||||
iter.fragment.size, | ||||||
(uint8_t *)curr->pixels, | ||||||
curr->pitch * curr->h, | ||||||
curr->pitch)) { | ||||||
iter.fragment.size, | ||||||
(uint8_t*)curr->pixels, | ||||||
curr->pitch * curr->h, | ||||||
curr->pitch)) { | ||||||
sezero marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
error = "WebPDecodeRGBAInto() failed"; | ||||||
SDL_FreeSurface(curr); | ||||||
goto error; | ||||||
} | ||||||
|
||||||
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; | ||||||
// Use BLENDMODE_NONE like in your implementation | ||||||
SDL_SetSurfaceBlendMode(curr, SDL_BLENDMODE_NONE); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do you handle WEBP_MUX_BLEND? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh right, what do you think of this?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clearing the region isn't necessary for BLENDMODE_NONE, the entire rectangle is copied from the source. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should just be able to use the original code: if (iter.blend_method == WEBP_MUX_BLEND) {
SDL_SetSurfaceBlendMode(curr, SDL_BLENDMODE_BLEND);
} else {
SDL_SetSurfaceBlendMode(curr, SDL_BLENDMODE_NONE);
} |
||||||
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; | ||||||
|
||||||
// Save current frame region and disposal method for next iteration | ||||||
prevRect = dst; | ||||||
dispose_method = iter.dispose_method; | ||||||
|
||||||
} while (lib.WebPDemuxNextFrame(&iter)); | ||||||
|
||||||
lib.WebPDemuxReleaseIterator(&iter); | ||||||
} | ||||||
|
||||||
SDL_FreeSurface(prevCanvas); | ||||||
SDL_FreeSurface(canvas); | ||||||
|
||||||
lib.WebPDemuxDelete(demuxer); | ||||||
|
||||||
SDL_free(raw_data); | ||||||
|
||||||
return anim; | ||||||
|
||||||
error: | ||||||
if (prevCanvas) { | ||||||
SDL_FreeSurface(prevCanvas); | ||||||
} | ||||||
if (canvas) { | ||||||
SDL_FreeSurface(canvas); | ||||||
} | ||||||
if (anim) { | ||||||
IMG_FreeAnimation(anim); | ||||||
if (anim->frames) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What did IMG_FreeAnimation() do that we don't want done here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I returned the error goto to how it was originally, hopefully fixed up formatting too |
||||||
for (int i = 0; i < anim->count; ++i) { | ||||||
if (anim->frames[i]) { | ||||||
SDL_FreeSurface(anim->frames[i]); | ||||||
} | ||||||
} | ||||||
SDL_free(anim->frames); | ||||||
} | ||||||
if (anim->delays) { | ||||||
SDL_free(anim->delays); | ||||||
} | ||||||
SDL_free(anim); | ||||||
} | ||||||
if (demuxer) { | ||||||
lib.WebPDemuxDelete(demuxer); | ||||||
} | ||||||
if (raw_data) { | ||||||
SDL_free(raw_data); | ||||||
} | ||||||
|
||||||
if (error) { | ||||||
IMG_SetError("%s", error); | ||||||
} | ||||||
SDL_RWseek(src, start, RW_SEEK_SET); | ||||||
|
||||||
return NULL; | ||||||
} | ||||||
|
||||||
#else | ||||||
#if _MSC_VER >= 1300 | ||||||
#pragma warning(disable : 4100) /* warning C4100: 'op' : unreferenced formal parameter */ | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure we should use transparency for alpha? is bgcolor a transparent pixel in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see white in the non-updated areas if not starting with alpha.
Investigation reveals many viewers just ignore background color entirely.
https://developers.google.com/speed/webp/docs/riff_container#animation
Kind of vague.
Some discussion on the matter:
SixLabors/ImageSharp#2547