hidefromkgb / gif_load

A slim, fast and header-only GIF loader written in C
80 stars 6 forks source link

How to read GIF into memory #12

Closed liqi0126 closed 3 years ago

liqi0126 commented 3 years ago

image

Thanks for your great repo firstly! However, since I barely know anything about GIF, it still bothers me how to read a gif file into a data structure like above?

fire-eggs commented 3 years ago

The main thing you need to know about GIF compared to other formats, is GIF is palette based. To wit, a pixel's color is not defined by four values of (R,G,B,A) but an index into a color table.

The example in readme.md essentially is doing what you want. The changes you need to make to that example include:

The BGRA macro in the readme.md example is what translates the GIF palette index into (I'm guessing) a BGRA entity. If you really want RGBA format, you'll need to modify that macro to change the byte order.

In the Frame() function in the example, the pict variable is the equivalent of your data member in your GIF_FRAME. So I'm thinking off-hand that you can set data to the value of pict at the end of Frame().

GIF_FRAME.width and GIF_FRAME.height come from whdr->xdim and whdr->ydim, respectively.

hidefromkgb commented 3 years ago

I`m here just to confirm that everything @fire-eggs said is correct.

A little addition: if you want to store partial frames to save RAM then you`ll definitely need width and height inside GIF_FRAME — but you`ll also need frame offsets as well as frame blending modes; the corresponding values in whdr are frxd (partial frame width), fryd (partial frame height), frxo (partial frame X offset), fryo (partial frame Y offset), and mode (see the readme for details).\ Otherwise there is virtually no need to store global GIF dimensions in each frame, so maybe a better structure would look like this:

typedef struct GIF {
    uint32_t **frames;
    long width, height;
    long frame_num;
    long curr_frame;
}

Or, since the total size of all frames is easily predictable,

typedef struct GIF {
    uint32_t *frames;
    long width, height;
    long frame_num;
    long curr_frame;
}

— so that frames would only require one dereferencing (frames[curr_frame * width * height + y * width + x]) instead of two (frames[curr_frame][y * width + x]).

P.S.: Please don`t forget that frames have delays, and ignoring them altogether will make GIFs play at a wrong speed, so if you want to play a GIF exactly it as it was intended then you`ll also need to store delays.

liqi0126 commented 3 years ago

It really works like a charm. Thanks a lot!