Skip to content

Commit

Permalink
Added support for loading animated GIFs
Browse files Browse the repository at this point in the history
  • Loading branch information
slouken committed Oct 4, 2019
1 parent f5eef6b commit b1300c4
Show file tree
Hide file tree
Showing 7 changed files with 574 additions and 89 deletions.
4 changes: 4 additions & 0 deletions CHANGES.txt
@@ -1,3 +1,7 @@
2.0.6:
Sam Lantinga - Thu Oct 3 18:09:17 PDT 2019
* Added support for loading animated GIFs

2.0.5:
Sam Lantinga - Wed Jun 19 07:30:51 PDT 2019
* Updated external libraries libpng-1.6.32, libwebp-1.0.2
Expand Down
139 changes: 126 additions & 13 deletions IMG.c
Expand Up @@ -27,7 +27,6 @@
#include <emscripten/emscripten.h>
#endif

#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))

/* Table of image detection and loading functions */
static struct {
Expand All @@ -54,6 +53,16 @@ static struct {
{ "WEBP", IMG_isWEBP, IMG_LoadWEBP_RW },
};

/* Table of animation detection and loading functions */
static struct {
const char *type;
int (SDLCALL *is)(SDL_RWops *src);
IMG_Animation *(SDLCALL *load)(SDL_RWops *src);
} supported_anims[] = {
/* keep magicless formats first */
{ "GIF", IMG_isGIF, IMG_LoadGIFAnimation_RW },
};

const SDL_version *IMG_Linked_Version(void)
{
static SDL_version linked_version;
Expand Down Expand Up @@ -146,10 +155,10 @@ SDL_Surface *IMG_Load(const char *file)

SDL_RWops *src = SDL_RWFromFile(file, "rb");
const char *ext = SDL_strrchr(file, '.');
if(ext) {
if (ext) {
ext++;
}
if(!src) {
if (!src) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
Expand Down Expand Up @@ -191,7 +200,7 @@ SDL_Surface *IMG_LoadTyped_RW(SDL_RWops *src, int freesrc, const char *type)
/* See whether or not this data source can handle seeking */
if ( SDL_RWseek(src, 0, RW_SEEK_CUR) < 0 ) {
IMG_SetError("Can't seek in this data source");
if(freesrc)
if (freesrc)
SDL_RWclose(src);
return(NULL);
}
Expand All @@ -206,15 +215,15 @@ SDL_Surface *IMG_LoadTyped_RW(SDL_RWops *src, int freesrc, const char *type)

data = emscripten_get_preloaded_image_data_from_FILE(src->hidden.stdio.fp, &w, &h);

if(data)
if (data)
{
surf = SDL_CreateRGBSurface(0, w, h, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
if (surf != NULL) {
memcpy(surf->pixels, data, w * h * 4);
}
free(data);

if(freesrc)
if (freesrc)
SDL_RWclose(src);

/* If SDL_CreateRGBSurface returns NULL, it has set the error message for us */
Expand All @@ -224,23 +233,21 @@ SDL_Surface *IMG_LoadTyped_RW(SDL_RWops *src, int freesrc, const char *type)
#endif

/* Detect the type of image being loaded */
image = NULL;
for ( i=0; i < ARRAYSIZE(supported); ++i ) {
if(supported[i].is) {
if(!supported[i].is(src))
for ( i=0; i < SDL_arraysize(supported); ++i ) {
if (supported[i].is) {
if (!supported[i].is(src))
continue;
} else {
/* magicless format */
if(!type
|| !IMG_string_equals(type, supported[i].type))
if (!type || !IMG_string_equals(type, supported[i].type))
continue;
}
#ifdef DEBUG_IMGLIB
fprintf(stderr, "IMGLIB: Loading image as %s\n",
supported[i].type);
#endif
image = supported[i].load(src);
if(freesrc)
if (freesrc)
SDL_RWclose(src);
return image;
}
Expand Down Expand Up @@ -286,3 +293,109 @@ SDL_Texture *IMG_LoadTextureTyped_RW(SDL_Renderer *renderer, SDL_RWops *src, int
return texture;
}
#endif /* SDL 2.0 */

/* Load an animation from a file */
IMG_Animation *IMG_LoadAnimation(const char *file)
{
SDL_RWops *src = SDL_RWFromFile(file, "rb");
const char *ext = SDL_strrchr(file, '.');
if (ext) {
ext++;
}
if (!src) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
return IMG_LoadAnimationTyped_RW(src, 1, ext);
}

/* Load an animation from an SDL datasource (for compatibility) */
IMG_Animation *IMG_LoadAnimation_RW(SDL_RWops *src, int freesrc)
{
return IMG_LoadAnimationTyped_RW(src, freesrc, NULL);
}

/* Load an animation from an SDL datasource, optionally specifying the type */
IMG_Animation *IMG_LoadAnimationTyped_RW(SDL_RWops *src, int freesrc, const char *type)
{
int i;
IMG_Animation *anim;
SDL_Surface *image;

/* Make sure there is something to do.. */
if ( src == NULL ) {
IMG_SetError("Passed a NULL data source");
return(NULL);
}

/* See whether or not this data source can handle seeking */
if ( SDL_RWseek(src, 0, RW_SEEK_CUR) < 0 ) {
IMG_SetError("Can't seek in this data source");
if (freesrc)
SDL_RWclose(src);
return(NULL);
}

/* Detect the type of image being loaded */
for ( i=0; i < SDL_arraysize(supported_anims); ++i ) {
if (supported_anims[i].is) {
if (!supported_anims[i].is(src))
continue;
} else {
/* magicless format */
if (!type || !IMG_string_equals(type, supported_anims[i].type))
continue;
}
#ifdef DEBUG_IMGLIB
fprintf(stderr, "IMGLIB: Loading image as %s\n",
supported_anims[i].type);
#endif
anim = supported_anims[i].load(src);
if (freesrc)
SDL_RWclose(src);
return anim;
}

/* Create a single frame animation from an image */
image = IMG_LoadTyped_RW(src, freesrc, type);
if (image) {
anim = (IMG_Animation *)SDL_malloc(sizeof(*anim));
if (anim) {
anim->w = image->w;
anim->h = image->h;
anim->count = 1;

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) {
anim->frames[0] = image;
return anim;
}
IMG_FreeAnimation(anim);
}
SDL_FreeSurface(image);
SDL_OutOfMemory();
}
return NULL;
}

void IMG_FreeAnimation(IMG_Animation *anim)
{
if (anim) {
if (anim->frames) {
int i;
for (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);
}
}

0 comments on commit b1300c4

Please sign in to comment.