From 838cd9fe90476f0dbdce360b570edb97d7cf1ee8 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 14 Aug 2025 14:34:02 -0700
Subject: [PATCH] Minor cleanup
This also makes it so decoders are responsible for setting IMG_DECODER_STATUS_COMPLETE, so IMG_GetAnimationDecoderFrame() knows to clear any lingering SDL error state.
---
VisualC/SDL_image.vcxproj | 6 +++---
VisualC/SDL_image.vcxproj.filters | 6 ++++++
include/SDL3_image/SDL_image.h | 30 +++++++++++++++---------------
src/IMG_anim_decoder.c | 18 +++++++-----------
src/IMG_anim_encoder.c | 5 ++---
src/IMG_anim_encoder.h | 2 +-
src/IMG_avif.c | 2 ++
src/IMG_gif.c | 1 +
src/IMG_libpng.c | 1 +
src/IMG_webp.c | 7 ++++---
10 files changed, 42 insertions(+), 36 deletions(-)
diff --git a/VisualC/SDL_image.vcxproj b/VisualC/SDL_image.vcxproj
index 1f1655ff..49a6b45f 100644
--- a/VisualC/SDL_image.vcxproj
+++ b/VisualC/SDL_image.vcxproj
@@ -219,6 +219,7 @@
<ClCompile Include="..\src\IMG_xcf.c" />
<ClCompile Include="..\src\IMG_xpm.c" />
<ClCompile Include="..\src\IMG_xv.c" />
+ <ClCompile Include="..\src\xmlman.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\src\version.rc" />
@@ -230,6 +231,7 @@
<ClInclude Include="..\src\IMG_libpng.h" />
<ClInclude Include="..\src\IMG_gif.h" />
<ClInclude Include="..\src\IMG_avif.h" />
+ <ClInclude Include="..\src\xmlman.h" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="external\optional\x64\libavif-16.dll">
@@ -436,6 +438,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-
-</Project>
-
+</Project>
\ No newline at end of file
diff --git a/VisualC/SDL_image.vcxproj.filters b/VisualC/SDL_image.vcxproj.filters
index 04309215..5ac3ea57 100644
--- a/VisualC/SDL_image.vcxproj.filters
+++ b/VisualC/SDL_image.vcxproj.filters
@@ -70,6 +70,9 @@
<ClCompile Include="..\src\IMG_anim_decoder.c">
<Filter>Sources</Filter>
</ClCompile>
+ <ClCompile Include="..\src\xmlman.c">
+ <Filter>Sources</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="Sources">
@@ -104,6 +107,9 @@
<ClInclude Include="..\src\IMG_anim_decoder.h">
<Filter>Sources</Filter>
</ClInclude>
+ <ClInclude Include="..\src\xmlman.h">
+ <Filter>Sources</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\src\version.rc">
diff --git a/include/SDL3_image/SDL_image.h b/include/SDL3_image/SDL_image.h
index 00c83552..2a923062 100644
--- a/include/SDL3_image/SDL_image.h
+++ b/include/SDL3_image/SDL_image.h
@@ -2403,20 +2403,6 @@ extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadGIFAnimation_IO(SDL_IOStream
*/
extern SDL_DECLSPEC IMG_Animation * SDLCALL IMG_LoadWEBPAnimation_IO(SDL_IOStream *src);
-/**
- * An enum representing the status of the encoder and decoder.
- *
- * \since This enum is available since SDL_image 3.4.0.
- */
-typedef enum IMG_AnimationDecoderStatus
-{
- IMG_DECODER_STATUS_OK, /**< Decoded the frame successfully. */
- IMG_DECODER_STATUS_FAILED, /**< Decoding the frame failed. Call SDL_GetError for more information. */
- IMG_DECODER_STATUS_COMPLETE, /**< No more frames available. */
-
- IMG_DECODER_STATUS_INVALID /**< Invalid decoder status that does not represent any valid status. */
-} IMG_AnimationDecoderStatus;
-
/**
* An object representing the encoder context.
*/
@@ -2553,6 +2539,19 @@ extern SDL_DECLSPEC bool SDLCALL IMG_AddAnimationEncoderFrame(IMG_AnimationEncod
*/
extern SDL_DECLSPEC bool SDLCALL IMG_CloseAnimationEncoder(IMG_AnimationEncoder *encoder);
+/**
+ * An enum representing the status of an animation decoder.
+ *
+ * \since This enum is available since SDL_image 3.4.0.
+ */
+typedef enum IMG_AnimationDecoderStatus
+{
+ IMG_DECODER_STATUS_INVALID = -1, /**< The decoder is invalid */
+ IMG_DECODER_STATUS_OK, /**< The decoder is ready to decode the next frame */
+ IMG_DECODER_STATUS_FAILED, /**< The decoder failed to decode a frame, call SDL_GetError() for more information. */
+ IMG_DECODER_STATUS_COMPLETE /**< No more frames available */
+} IMG_AnimationDecoderStatus;
+
/**
* An object representing animation decoder.
*/
@@ -2690,13 +2689,14 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL IMG_GetAnimationDecoderProperties(I
* `IMG_PROP_ANIMATION_DECODER_CREATE_TIMEBASE_DENOMINATOR_NUMBER`
* property is set when creating the decoder.
* \returns true on success or false on failure and when no more frames are
- * available; call SDL_GetError() for more information.
+ * available; call IMG_GetAnimationDecoderStatus() or SDL_GetError() for more information.
*
* \since This function is available since SDL_image 3.4.0.
*
* \sa IMG_CreateAnimationDecoder
* \sa IMG_CreateAnimationDecoder_IO
* \sa IMG_CreateAnimationDecoderWithProperties
+ * \sa IMG_GetAnimationDecoderStatus
* \sa IMG_ResetAnimationDecoder
* \sa IMG_CloseAnimationDecoder
*/
diff --git a/src/IMG_anim_decoder.c b/src/IMG_anim_decoder.c
index e4f1fb1c..6268714c 100644
--- a/src/IMG_anim_decoder.c
+++ b/src/IMG_anim_decoder.c
@@ -193,8 +193,8 @@ bool IMG_GetAnimationDecoderFrame(IMG_AnimationDecoder *decoder, SDL_Surface **f
if (!duration) {
duration = &temp_duration;
}
- SDL_ClearError();
- // Reset the status before trying to get the next frame.
+
+ // Reset the status before trying to get the next frame
decoder->status = IMG_DECODER_STATUS_OK;
bool result = decoder->GetNextFrame(decoder, frame, duration);
@@ -202,17 +202,14 @@ bool IMG_GetAnimationDecoderFrame(IMG_AnimationDecoder *decoder, SDL_Surface **f
SDL_DestroySurface(temp_frame);
}
- if (!result) {
- if (SDL_GetError()[0] == '\0') {
- decoder->status = IMG_DECODER_STATUS_COMPLETE;
- } else {
- decoder->status = IMG_DECODER_STATUS_FAILED;
- }
- }
-
if (result) {
decoder->accumulated_pts += *duration;
} else {
+ if (decoder->status == IMG_DECODER_STATUS_COMPLETE) {
+ SDL_ClearError();
+ } else {
+ decoder->status = IMG_DECODER_STATUS_FAILED;
+ }
*frame = NULL;
*duration = 0;
}
@@ -263,7 +260,6 @@ IMG_AnimationDecoderStatus IMG_GetAnimationDecoderStatus(IMG_AnimationDecoder* d
if (!decoder) {
return IMG_DECODER_STATUS_INVALID;
}
-
return decoder->status;
}
diff --git a/src/IMG_anim_encoder.c b/src/IMG_anim_encoder.c
index eecacd26..7c9ec23f 100644
--- a/src/IMG_anim_encoder.c
+++ b/src/IMG_anim_encoder.c
@@ -171,13 +171,12 @@ bool IMG_AddAnimationEncoderFrame(IMG_AnimationEncoder *encoder, SDL_Surface *su
if (!surface || surface->w <= 0 || surface->h <= 0) {
return SDL_InvalidParamError("surface");
}
- bool result = encoder->AddFrame(encoder, surface, duration);
+ bool result = encoder->AddFrame(encoder, surface, duration);
if (result) {
encoder->accumulated_pts += duration;
- encoder->last_delay = duration;
+ encoder->last_duration = duration;
}
-
return result;
}
diff --git a/src/IMG_anim_encoder.h b/src/IMG_anim_encoder.h
index fd413bf7..cded6f2b 100644
--- a/src/IMG_anim_encoder.h
+++ b/src/IMG_anim_encoder.h
@@ -30,7 +30,7 @@ struct IMG_AnimationEncoder
int timebase_numerator;
int timebase_denominator;
Uint64 accumulated_pts;
- Uint64 last_delay;
+ Uint64 last_duration;
bool (*AddFrame)(IMG_AnimationEncoder *encoder, SDL_Surface *surface, Uint64 duration);
bool (*Close)(IMG_AnimationEncoder *encoder);
diff --git a/src/IMG_avif.c b/src/IMG_avif.c
index 62e7de29..2c0d02d2 100644
--- a/src/IMG_avif.c
+++ b/src/IMG_avif.c
@@ -890,6 +890,7 @@ static bool IMG_AnimationDecoderGetNextFrame_Internal(IMG_AnimationDecoder *deco
avifResult result;
if (ctx->total_frames - ctx->current_frame < 1) {
+ decoder->status = IMG_DECODER_STATUS_COMPLETE;
return false;
}
@@ -897,6 +898,7 @@ static bool IMG_AnimationDecoderGetNextFrame_Internal(IMG_AnimationDecoder *deco
if (result != AVIF_RESULT_OK) {
if (result == AVIF_RESULT_NO_IMAGES_REMAINING) {
// This shouldn't happen here, but handle it gracefully
+ decoder->status = IMG_DECODER_STATUS_COMPLETE;
return false;
}
diff --git a/src/IMG_gif.c b/src/IMG_gif.c
index 48179214..364af15f 100644
--- a/src/IMG_gif.c
+++ b/src/IMG_gif.c
@@ -757,6 +757,7 @@ static bool IMG_AnimationDecoderGetNextFrame_Internal(IMG_AnimationDecoder *deco
int framesLoaded = 0;
if (ctx->got_eof) {
+ decoder->status = IMG_DECODER_STATUS_COMPLETE;
return false;
}
diff --git a/src/IMG_libpng.c b/src/IMG_libpng.c
index 9398cd67..18773ee9 100644
--- a/src/IMG_libpng.c
+++ b/src/IMG_libpng.c
@@ -1147,6 +1147,7 @@ static bool IMG_AnimationDecoderGetNextFrame_Internal(IMG_AnimationDecoder *deco
}
if (ctx->actl.num_frames - ctx->current_frame_index < 1) {
+ decoder->status = IMG_DECODER_STATUS_COMPLETE;
return false;
}
diff --git a/src/IMG_webp.c b/src/IMG_webp.c
index 0bd172f5..be7ca0be 100644
--- a/src/IMG_webp.c
+++ b/src/IMG_webp.c
@@ -436,11 +436,11 @@ static bool IMG_AnimationDecoderGetNextFrame_Internal(IMG_AnimationDecoder *deco
// Get the next frame from the demuxer.
if (decoder->ctx->iter.frame_num < 1) {
if (!lib.WebPDemuxGetFrame(decoder->ctx->demuxer, 1, &decoder->ctx->iter)) {
- SDL_SetError("Failed to get first frame from WEBP demuxer");
- return false;
+ return SDL_SetError("Failed to get first frame from WEBP demuxer");
}
} else {
if (!lib.WebPDemuxNextFrame(&decoder->ctx->iter)) {
+ decoder->status = IMG_DECODER_STATUS_COMPLETE;
return false;
}
}
@@ -449,6 +449,7 @@ static bool IMG_AnimationDecoderGetNextFrame_Internal(IMG_AnimationDecoder *deco
int availableFrames = totalFrames - (decoder->ctx->iter.frame_num - 1);
if (availableFrames < 1) {
+ decoder->status = IMG_DECODER_STATUS_COMPLETE;
return false;
}
@@ -915,7 +916,7 @@ static bool IMG_CloseWEBPAnimation(IMG_AnimationEncoder *encoder)
goto done;
}
- int timestamp = (int)IMG_GetCurrentTimestamp(encoder, encoder->last_delay, 1000);
+ int timestamp = (int)IMG_GetCurrentTimestamp(encoder, encoder->last_duration, 1000);
if (!lib.WebPAnimEncoderAdd(ctx->encoder, NULL, timestamp, &ctx->config)) {
error = "WebPAnimEncoderAdd() failed";
goto done;