|
@@ -75,7 +75,7 @@ RECENT REVISION HISTORY:
|
|
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
|
|
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
|
|
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
|
|
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
|
|
github:urraka (animated gif) Junggon Kim (PNM comments)
|
|
github:urraka (animated gif) Junggon Kim (PNM comments)
|
|
- Daniel Gibson (16-bit TGA)
|
|
|
|
|
|
+ github:tocchan (animated gif) Daniel Gibson (16-bit TGA)
|
|
socks-the-fox (16-bit PNG)
|
|
socks-the-fox (16-bit PNG)
|
|
Jeremy Sawicki (handle all ImageNet JPGs)
|
|
Jeremy Sawicki (handle all ImageNet JPGs)
|
|
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
|
|
Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
|
|
@@ -355,6 +355,10 @@ typedef struct
|
|
|
|
|
|
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
|
|
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
|
|
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
|
|
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
|
|
|
|
+#ifndef STBI_NO_GIF
|
|
|
|
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
|
|
#ifndef STBI_NO_STDIO
|
|
#ifndef STBI_NO_STDIO
|
|
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
|
|
STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
|
|
@@ -826,6 +830,7 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
|
|
#ifndef STBI_NO_GIF
|
|
#ifndef STBI_NO_GIF
|
|
static int stbi__gif_test(stbi__context *s);
|
|
static int stbi__gif_test(stbi__context *s);
|
|
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
|
|
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
|
|
|
|
+static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
|
|
static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
|
|
static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
@@ -1065,6 +1070,18 @@ static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)
|
|
|
|
+{
|
|
|
|
+ int slice;
|
|
|
|
+ int slice_size = w * h * bytes_per_pixel;
|
|
|
|
+
|
|
|
|
+ stbi_uc *bytes = (stbi_uc *)image;
|
|
|
|
+ for (slice = 0; slice < z; ++slice) {
|
|
|
|
+ stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
|
|
|
|
+ bytes += slice_size;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
|
static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
|
{
|
|
{
|
|
stbi__result_info ri;
|
|
stbi__result_info ri;
|
|
@@ -1216,6 +1233,21 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u
|
|
return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
|
|
return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifndef STBI_NO_GIF
|
|
|
|
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
|
|
|
|
+{
|
|
|
|
+ stbi__context s;
|
|
|
|
+ stbi__start_mem(&s,buffer,len);
|
|
|
|
+
|
|
|
|
+ unsigned char *result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
|
|
|
|
+ if (stbi__vertically_flip_on_load) {
|
|
|
|
+ stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
#ifndef STBI_NO_LINEAR
|
|
#ifndef STBI_NO_LINEAR
|
|
static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
|
static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
|
|
{
|
|
{
|
|
@@ -6085,11 +6117,13 @@ typedef struct
|
|
typedef struct
|
|
typedef struct
|
|
{
|
|
{
|
|
int w,h;
|
|
int w,h;
|
|
- stbi_uc *out, *old_out; // output buffer (always 4 components)
|
|
|
|
- int flags, bgindex, ratio, transparent, eflags, delay;
|
|
|
|
|
|
+ stbi_uc *out; // output buffer (always 4 components)
|
|
|
|
+ stbi_uc *background; // The current "background" as far as a gif is concerned
|
|
|
|
+ stbi_uc *history;
|
|
|
|
+ int flags, bgindex, ratio, transparent, eflags;
|
|
stbi_uc pal[256][4];
|
|
stbi_uc pal[256][4];
|
|
stbi_uc lpal[256][4];
|
|
stbi_uc lpal[256][4];
|
|
- stbi__gif_lzw codes[4096];
|
|
|
|
|
|
+ stbi__gif_lzw codes[8192];
|
|
stbi_uc *color_table;
|
|
stbi_uc *color_table;
|
|
int parse, step;
|
|
int parse, step;
|
|
int lflags;
|
|
int lflags;
|
|
@@ -6097,6 +6131,7 @@ typedef struct
|
|
int max_x, max_y;
|
|
int max_x, max_y;
|
|
int cur_x, cur_y;
|
|
int cur_x, cur_y;
|
|
int line_size;
|
|
int line_size;
|
|
|
|
+ int delay;
|
|
} stbi__gif;
|
|
} stbi__gif;
|
|
|
|
|
|
static int stbi__gif_test_raw(stbi__context *s)
|
|
static int stbi__gif_test_raw(stbi__context *s)
|
|
@@ -6172,6 +6207,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
|
|
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
|
|
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
|
|
{
|
|
{
|
|
stbi_uc *p, *c;
|
|
stbi_uc *p, *c;
|
|
|
|
+ int idx;
|
|
|
|
|
|
// recurse to decode the prefixes, since the linked-list is backwards,
|
|
// recurse to decode the prefixes, since the linked-list is backwards,
|
|
// and working backwards through an interleaved image would be nasty
|
|
// and working backwards through an interleaved image would be nasty
|
|
@@ -6180,10 +6216,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
|
|
|
|
|
|
if (g->cur_y >= g->max_y) return;
|
|
if (g->cur_y >= g->max_y) return;
|
|
|
|
|
|
- p = &g->out[g->cur_x + g->cur_y];
|
|
|
|
- c = &g->color_table[g->codes[code].suffix * 4];
|
|
|
|
|
|
+ idx = g->cur_x + g->cur_y;
|
|
|
|
+ p = &g->out[idx];
|
|
|
|
+ g->history[idx / 4] = 1;
|
|
|
|
|
|
- if (c[3] >= 128) {
|
|
|
|
|
|
+ c = &g->color_table[g->codes[code].suffix * 4];
|
|
|
|
+ if (c[3] > 128) { // don't render transparent pixels;
|
|
p[0] = c[2];
|
|
p[0] = c[2];
|
|
p[1] = c[1];
|
|
p[1] = c[1];
|
|
p[2] = c[0];
|
|
p[2] = c[0];
|
|
@@ -6257,11 +6295,16 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
|
|
stbi__skip(s,len);
|
|
stbi__skip(s,len);
|
|
return g->out;
|
|
return g->out;
|
|
} else if (code <= avail) {
|
|
} else if (code <= avail) {
|
|
- if (first) return stbi__errpuc("no clear code", "Corrupt GIF");
|
|
|
|
|
|
+ if (first) {
|
|
|
|
+ return stbi__errpuc("no clear code", "Corrupt GIF");
|
|
|
|
+ }
|
|
|
|
|
|
if (oldcode >= 0) {
|
|
if (oldcode >= 0) {
|
|
p = &g->codes[avail++];
|
|
p = &g->codes[avail++];
|
|
- if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF");
|
|
|
|
|
|
+ if (avail > 8192) {
|
|
|
|
+ return stbi__errpuc("too many codes", "Corrupt GIF");
|
|
|
|
+ }
|
|
|
|
+
|
|
p->prefix = (stbi__int16) oldcode;
|
|
p->prefix = (stbi__int16) oldcode;
|
|
p->first = g->codes[oldcode].first;
|
|
p->first = g->codes[oldcode].first;
|
|
p->suffix = (code == avail) ? p->first : g->codes[code].first;
|
|
p->suffix = (code == avail) ? p->first : g->codes[code].first;
|
|
@@ -6283,62 +6326,72 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)
|
|
|
|
-{
|
|
|
|
- int x, y;
|
|
|
|
- stbi_uc *c = g->pal[g->bgindex];
|
|
|
|
- for (y = y0; y < y1; y += 4 * g->w) {
|
|
|
|
- for (x = x0; x < x1; x += 4) {
|
|
|
|
- stbi_uc *p = &g->out[y + x];
|
|
|
|
- p[0] = c[2];
|
|
|
|
- p[1] = c[1];
|
|
|
|
- p[2] = c[0];
|
|
|
|
- p[3] = 0;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
// this function is designed to support animated gifs, although stb_image doesn't support it
|
|
// this function is designed to support animated gifs, although stb_image doesn't support it
|
|
-static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp)
|
|
|
|
-{
|
|
|
|
- int i;
|
|
|
|
- stbi_uc *prev_out = 0;
|
|
|
|
-
|
|
|
|
- if (g->out == 0 && !stbi__gif_header(s, g, comp,0))
|
|
|
|
- return 0; // stbi__g_failure_reason set by stbi__gif_header
|
|
|
|
-
|
|
|
|
- if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0))
|
|
|
|
- return stbi__errpuc("too large", "GIF too large");
|
|
|
|
|
|
+// two back is the image from two frames ago, used for a very specific disposal format
|
|
|
|
+static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
|
|
|
|
+{
|
|
|
|
+ int dispose;
|
|
|
|
+ int first_frame;
|
|
|
|
+ int pi;
|
|
|
|
+ int pcount;
|
|
|
|
+
|
|
|
|
+ // on first frame, any non-written pixels get the background colour (non-transparent)
|
|
|
|
+ first_frame = 0;
|
|
|
|
+ if (g->out == 0) {
|
|
|
|
+ if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
|
|
|
|
+ g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
|
|
|
|
+ g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
|
|
|
|
+ g->history = (stbi_uc *) stbi__malloc(g->w * g->h);
|
|
|
|
+ if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
|
|
|
|
+
|
|
|
|
+ // image is treated as "tranparent" at the start - ie, nothing overwrites the current background;
|
|
|
|
+ // background colour is only used for pixels that are not rendered first frame, after that "background"
|
|
|
|
+ // color refers to teh color that was there the previous frame.
|
|
|
|
+ memset( g->out, 0x00, 4 * g->w * g->h );
|
|
|
|
+ memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent)
|
|
|
|
+ memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
|
|
|
|
+ first_frame = 1;
|
|
|
|
+ } else {
|
|
|
|
+ // second frame - how do we dispoase of the previous one?
|
|
|
|
+ dispose = (g->eflags & 0x1C) >> 2;
|
|
|
|
+ pcount = g->w * g->h;
|
|
|
|
|
|
- prev_out = g->out;
|
|
|
|
- g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);
|
|
|
|
- if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
|
|
|
|
|
|
+ if ((dispose == 3) && (two_back == 0)) {
|
|
|
|
+ dispose = 2; // if I don't have an image to revert back to, default to the old background
|
|
|
|
+ }
|
|
|
|
|
|
- switch ((g->eflags & 0x1C) >> 2) {
|
|
|
|
- case 0: // unspecified (also always used on 1st frame)
|
|
|
|
- stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h);
|
|
|
|
- break;
|
|
|
|
- case 1: // do not dispose
|
|
|
|
- if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
|
|
|
|
- g->old_out = prev_out;
|
|
|
|
- break;
|
|
|
|
- case 2: // dispose to background
|
|
|
|
- if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
|
|
|
|
- stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y);
|
|
|
|
- break;
|
|
|
|
- case 3: // dispose to previous
|
|
|
|
- if (g->old_out) {
|
|
|
|
- for (i = g->start_y; i < g->max_y; i += 4 * g->w)
|
|
|
|
- memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);
|
|
|
|
|
|
+ if (dispose == 3) { // use previous graphic
|
|
|
|
+ for (pi = 0; pi < pcount; ++pi) {
|
|
|
|
+ if (g->history[pi]) {
|
|
|
|
+ memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- break;
|
|
|
|
|
|
+ } else if (dispose == 2) {
|
|
|
|
+ // restore what was changed last frame to background before that frame;
|
|
|
|
+ for (pi = 0; pi < pcount; ++pi) {
|
|
|
|
+ if (g->history[pi]) {
|
|
|
|
+ memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // This is a non-disposal case eithe way, so just
|
|
|
|
+ // leave the pixels as is, and they will become the new background
|
|
|
|
+ // 1: do not dispose
|
|
|
|
+ // 0: not specified.
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // background is what out is after the undoing of the previou frame;
|
|
|
|
+ memcpy( g->background, g->out, 4 * g->w * g->h );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // clear my history;
|
|
|
|
+ memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
|
|
|
|
+
|
|
for (;;) {
|
|
for (;;) {
|
|
- switch (stbi__get8(s)) {
|
|
|
|
|
|
+ int tag = stbi__get8(s);
|
|
|
|
+ switch (tag) {
|
|
case 0x2C: /* Image Descriptor */
|
|
case 0x2C: /* Image Descriptor */
|
|
{
|
|
{
|
|
- int prev_trans = -1;
|
|
|
|
stbi__int32 x, y, w, h;
|
|
stbi__int32 x, y, w, h;
|
|
stbi_uc *o;
|
|
stbi_uc *o;
|
|
|
|
|
|
@@ -6371,19 +6424,24 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
|
stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
|
|
stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
|
|
g->color_table = (stbi_uc *) g->lpal;
|
|
g->color_table = (stbi_uc *) g->lpal;
|
|
} else if (g->flags & 0x80) {
|
|
} else if (g->flags & 0x80) {
|
|
- if (g->transparent >= 0 && (g->eflags & 0x01)) {
|
|
|
|
- prev_trans = g->pal[g->transparent][3];
|
|
|
|
- g->pal[g->transparent][3] = 0;
|
|
|
|
- }
|
|
|
|
g->color_table = (stbi_uc *) g->pal;
|
|
g->color_table = (stbi_uc *) g->pal;
|
|
} else
|
|
} else
|
|
- return stbi__errpuc("missing color table", "Corrupt GIF");
|
|
|
|
-
|
|
|
|
|
|
+ return stbi__errpuc("missing color table", "Corrupt GIF");
|
|
|
|
+
|
|
o = stbi__process_gif_raster(s, g);
|
|
o = stbi__process_gif_raster(s, g);
|
|
if (o == NULL) return NULL;
|
|
if (o == NULL) return NULL;
|
|
|
|
|
|
- if (prev_trans != -1)
|
|
|
|
- g->pal[g->transparent][3] = (stbi_uc) prev_trans;
|
|
|
|
|
|
+ // if this was the first frame,
|
|
|
|
+ pcount = g->w * g->h;
|
|
|
|
+ if (first_frame && (g->bgindex > 0)) {
|
|
|
|
+ // if first frame, any pixel not drawn to gets the background color
|
|
|
|
+ for (pi = 0; pi < pcount; ++pi) {
|
|
|
|
+ if (g->history[pi] == 0) {
|
|
|
|
+ g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
|
|
|
|
+ memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
return o;
|
|
return o;
|
|
}
|
|
}
|
|
@@ -6391,19 +6449,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
|
case 0x21: // Comment Extension.
|
|
case 0x21: // Comment Extension.
|
|
{
|
|
{
|
|
int len;
|
|
int len;
|
|
- if (stbi__get8(s) == 0xF9) { // Graphic Control Extension.
|
|
|
|
|
|
+ int ext = stbi__get8(s);
|
|
|
|
+ if (ext == 0xF9) { // Graphic Control Extension.
|
|
len = stbi__get8(s);
|
|
len = stbi__get8(s);
|
|
if (len == 4) {
|
|
if (len == 4) {
|
|
g->eflags = stbi__get8(s);
|
|
g->eflags = stbi__get8(s);
|
|
- g->delay = stbi__get16le(s);
|
|
|
|
- g->transparent = stbi__get8(s);
|
|
|
|
|
|
+ g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.
|
|
|
|
+
|
|
|
|
+ // unset old transparent
|
|
|
|
+ if (g->transparent >= 0) {
|
|
|
|
+ g->pal[g->transparent][3] = 255;
|
|
|
|
+ }
|
|
|
|
+ if (g->eflags & 0x01) {
|
|
|
|
+ g->transparent = stbi__get8(s);
|
|
|
|
+ if (g->transparent >= 0) {
|
|
|
|
+ g->pal[g->transparent][3] = 0;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // don't need transparent
|
|
|
|
+ stbi__skip(s, 1);
|
|
|
|
+ g->transparent = -1;
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
stbi__skip(s, len);
|
|
stbi__skip(s, len);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- }
|
|
|
|
- while ((len = stbi__get8(s)) != 0)
|
|
|
|
|
|
+ }
|
|
|
|
+ while ((len = stbi__get8(s)) != 0) {
|
|
stbi__skip(s, len);
|
|
stbi__skip(s, len);
|
|
|
|
+ }
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -6414,28 +6488,92 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
|
return stbi__errpuc("unknown code", "Corrupt GIF");
|
|
return stbi__errpuc("unknown code", "Corrupt GIF");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
|
|
|
|
+{
|
|
|
|
+ if (stbi__gif_test(s)) {
|
|
|
|
+ int layers = 0;
|
|
|
|
+ stbi_uc *u = 0;
|
|
|
|
+ stbi_uc *out = 0;
|
|
|
|
+ stbi_uc *two_back = 0;
|
|
|
|
+ stbi__gif g;
|
|
|
|
+ int stride;
|
|
|
|
+ memset(&g, 0, sizeof(g));
|
|
|
|
+ if (delays) {
|
|
|
|
+ *delays = 0;
|
|
|
|
+ }
|
|
|
|
|
|
- STBI_NOTUSED(req_comp);
|
|
|
|
|
|
+ do {
|
|
|
|
+ u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
|
|
|
|
+ if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
|
|
|
|
+
|
|
|
|
+ if (u) {
|
|
|
|
+ *x = g.w;
|
|
|
|
+ *y = g.h;
|
|
|
|
+ ++layers;
|
|
|
|
+ stride = g.w * g.h * 4;
|
|
|
|
+
|
|
|
|
+ if (out) {
|
|
|
|
+ out = (stbi_uc*) STBI_REALLOC( out, layers * stride );
|
|
|
|
+ if (delays) {
|
|
|
|
+ *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers );
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ out = (stbi_uc*)stbi__malloc( layers * stride );
|
|
|
|
+ if (delays) {
|
|
|
|
+ *delays = (int*) stbi__malloc( layers * sizeof(int) );
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ memcpy( out + ((layers - 1) * stride), u, stride );
|
|
|
|
+ if (layers >= 2) {
|
|
|
|
+ two_back = out - 2 * stride;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (delays) {
|
|
|
|
+ (*delays)[layers - 1U] = g.delay;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } while (u != 0);
|
|
|
|
+
|
|
|
|
+ // free temp buffer;
|
|
|
|
+ STBI_FREE(g.out);
|
|
|
|
+ STBI_FREE(g.history);
|
|
|
|
+ STBI_FREE(g.background);
|
|
|
|
+
|
|
|
|
+ // do the final conversion after loading everything;
|
|
|
|
+ if (req_comp && req_comp != 4)
|
|
|
|
+ out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
|
|
|
|
+
|
|
|
|
+ *z = layers;
|
|
|
|
+ return out;
|
|
|
|
+ } else {
|
|
|
|
+ return stbi__errpuc("not GIF", "Image was not as a gif type.");
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
|
|
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
|
|
{
|
|
{
|
|
stbi_uc *u = 0;
|
|
stbi_uc *u = 0;
|
|
- stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
|
|
|
|
- memset(g, 0, sizeof(*g));
|
|
|
|
- STBI_NOTUSED(ri);
|
|
|
|
|
|
+ stbi__gif g;
|
|
|
|
+ memset(&g, 0, sizeof(g));
|
|
|
|
|
|
- u = stbi__gif_load_next(s, g, comp, req_comp);
|
|
|
|
|
|
+ u = stbi__gif_load_next(s, &g, comp, req_comp, 0);
|
|
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
|
|
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
|
|
if (u) {
|
|
if (u) {
|
|
- *x = g->w;
|
|
|
|
- *y = g->h;
|
|
|
|
|
|
+ *x = g.w;
|
|
|
|
+ *y = g.h;
|
|
|
|
+
|
|
|
|
+ // moved conversion to after successful load so that the same
|
|
|
|
+ // can be done for multiple frames.
|
|
if (req_comp && req_comp != 4)
|
|
if (req_comp && req_comp != 4)
|
|
- u = stbi__convert_format(u, 4, req_comp, g->w, g->h);
|
|
|
|
|
|
+ u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
|
|
}
|
|
}
|
|
- else if (g->out)
|
|
|
|
- STBI_FREE(g->out);
|
|
|
|
- STBI_FREE(g);
|
|
|
|
|
|
+
|
|
|
|
+ // free buffers needed for multiple frame loading;
|
|
|
|
+ STBI_FREE(g.history);
|
|
|
|
+ STBI_FREE(g.background);
|
|
|
|
+
|
|
return u;
|
|
return u;
|
|
}
|
|
}
|
|
|
|
|