#define STB_IMAGE_IMPLEMENTATION | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#define STBI_ONLY_PNG | |
#define STBI_ONLY_JPEG | |
#define STBI_ONLY_BMP | |
#define STBI_ONLY_GIF | |
#include "stb_image.h" | |
#include "stb_image_write.h" | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
typedef struct gif_result_t { | |
int delay; | |
unsigned char *data; | |
struct gif_result_t *next; | |
} gif_result; | |
STBIDEF unsigned char *stbi_xload(char const *filename, int *x, int *y, int *frames) | |
{ | |
FILE *f; | |
stbi__context s; | |
unsigned char *result = 0; | |
if (!(f = stbi__fopen(filename, "rb"))) | |
return stbi__errpuc("can't fopen", "Unable to open file"); | |
stbi__start_file(&s, f); | |
if (stbi__gif_test(&s)) | |
{ | |
int c; | |
stbi__gif g; | |
gif_result head; | |
gif_result *prev = 0, *gr = &head; | |
memset(&g, 0, sizeof(g)); | |
memset(&head, 0, sizeof(head)); | |
*frames = 0; | |
while (gr->data = stbi__gif_load_next(&s, &g, &c, 4)) | |
{ | |
if (gr->data == (unsigned char*)&s) | |
{ | |
gr->data = 0; | |
break; | |
} | |
if (prev) prev->next = gr; | |
gr->delay = g.delay; | |
prev = gr; | |
gr = (gif_result*) stbi__malloc(sizeof(gif_result)); | |
memset(gr, 0, sizeof(gif_result)); | |
++(*frames); | |
} | |
STBI_FREE(g.out); | |
if (gr != &head) | |
STBI_FREE(gr); | |
if (*frames > 0) | |
{ | |
*x = g.w; | |
*y = g.h; | |
} | |
result = head.data; | |
if (*frames > 1) | |
{ | |
unsigned int size = 4 * g.w * g.h; | |
unsigned char *p = 0; | |
result = (unsigned char*)stbi__malloc(*frames * (size + 2)); | |
gr = &head; | |
p = result; | |
while (gr) | |
{ | |
prev = gr; | |
memcpy(p, gr->data, size); | |
p += size; | |
*p++ = gr->delay & 0xFF; | |
*p++ = (gr->delay & 0xFF00) >> 8; | |
gr = gr->next; | |
STBI_FREE(prev->data); | |
if (prev != &head) STBI_FREE(prev); | |
} | |
} | |
} | |
else | |
{ | |
result = stbi__load_main(&s, x, y, frames, 4); | |
*frames = !!result; | |
} | |
fclose(f); | |
return result; | |
} | |
#ifdef __cplusplus | |
} | |
#endif |
This comment has been minimized.
This comment has been minimized.
@urraka
To cut the story short, it seems that: As I said before, I'm not sure if this happens because of my (slight) modification of your code or if the leak happens in your code as well. I'm using stb_image - v2.10, and I'm here because a link to this gist is present in that file. |
This comment has been minimized.
This comment has been minimized.
I've managed to solve the memory leak this way in my code: gif_result (and gif_result_t) replacement: struct gif_result : stbi__gif {
unsigned char *data;
struct gif_result *next;
}; Then in lines 44 and below: while (gr->data = stbi__gif_load_next(&s, &g, &c, 4))
{
STBI_FREE(gr->out);gr->out=NULL; // New!
if (gr->data == (unsigned char*)&s)
{
gr->data = 0;
break;
}
if (prev) prev->next = gr;
gr->delay = g.delay;
prev = gr;
gr = (gif_result*) stbi__malloc(sizeof(gif_result));
memset(gr, 0, sizeof(gif_result));
++(*frames);
}
STBI_FREE(gr->out);gr->out=NULL; // New!
if (gr != &head)
STBI_FREE(gr); Still, I did these changes in my (slightly modified) code and I ported them to your code. |
This comment has been minimized.
This comment has been minimized.
I'm sorry I didn't reply earlier. GitHub didn't notify me of this and I just found your comment randomly. I won't claim that my code is free from memory leaks, but I see some issues with your changes. First, I'm going to assume that where you have Regarding your first "New!" line: You are freeing the image data as soon as you retrieve it. How could you possibly return any (valid) image data that way? Also note that after that line I'm comparing Second "New!" line: There are two conditions under which the Note that you are supposed to call |
This comment has been minimized.
This comment has been minimized.
Sorry from me too (same reason).
Actually now gr is an instance of gif_result, that derives from: typedef struct
{
int w,h;
stbi_uc *out, *old_out; // output buffer (always 4 components)
int flags, bgindex, ratio, transparent, eflags, delay;
stbi_uc pal[256][4];
stbi_uc lpal[256][4];
stbi__gif_lzw codes[4096];
stbi_uc *color_table;
int parse, step;
int lflags;
int start_x, start_y;
int max_x, max_y;
int cur_x, cur_y;
int line_size;
} stbi__gif; So there is gr->out (I'm using stb_image.h version 2.10). That told, I'm aware that my code might have problems... some of your observations seem correct to me. The problem is just that with the code you posted I have memory leaks, and I did not find another way to get rid of them :(. |
This comment has been minimized.
This comment has been minimized.
Woops, I totally missed the inheritance you had there... Anyway, I don't remember exactly how I think you can remove the |
This comment has been minimized.
This comment has been minimized.
I had the same impression... but in the (2 or 3) .gifs I've tried so far, Valgrind still gives me a memory leak if I comment out the
If typedef struct
{
stbi__uint32 img_x, img_y;
int img_n, img_out_n;
stbi_io_callbacks io;
void *io_user_data;
int read_from_callbacks;
int buflen;
stbi_uc buffer_start[128];
stbi_uc *img_buffer, *img_buffer_end;
stbi_uc *img_buffer_original, *img_buffer_original_end;
} stbi__context; So I don't know which one to try... |
This comment has been minimized.
This comment has been minimized.
I'm sorry: on a closer look the memory leaks seem to be still present even with my (horrible and incorrect) 'fix'. |
This comment has been minimized.
This comment has been minimized.
Sorry, |
This comment has been minimized.
This comment has been minimized.
I tested with some sample gifs. Adding |
This comment has been minimized.
This comment has been minimized.
Yes! This worked for me too (tested with 2 different gifs: no more leaks!) Thanks. |
This comment has been minimized.
This comment has been minimized.
Cool. It's updated now. |
This comment has been minimized.
This comment has been minimized.
This code is outdated. Multiple functions of stbi_image have been changed so this code doesn't work anymore: In line 44: In line 98: Is there any way to make it work with the current functions? What has changed since 2016? There is still a link to this piece of code as a GIF loader solution. |
This comment has been minimized.
This comment has been minimized.
Hey @Gtoyos, I suggest that you look into |
This comment has been minimized.
Notes:
stbi_xload
returns a buffer with all frames like [image#0][delay#0][image#1][delay#1][...].frames
parameter.x
,y
parameters.