Giter Club home page Giter Club logo

gifdec's Introduction

Hi there

I write lightweight programs and libraries, mostly using C and LuaJIT.

Some of my current interests are 2D graphics, MIDI sequencers, UNIX tools and HTTP.

Many of my projects are released into the public domain, so you can use the code freely for any purpose.

I'm in the process of reducing reliance on GitHub. Eventually you'll find my stuff on lecram.dev.br. Recent code is already being pushed to git.lecram.dev.br.

Currently I'm unable to work on issues/PRs posted on my GitHub repos, sorry.

There's still some old stuff at lecram.github.io.

gifdec's People

Contributors

lecram avatar michielp1807 avatar sr-tream avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gifdec's Issues

Timing

When playing this animation back, using gif->gce.delay as the replay between frames, it doesn't work properly. Most frames only last for 1 render.

eyeroll

In Windows Environment Crash

I porting the code to QT environment and MinGW32 GCC environment, both of them same crash, and found the code will crash at read_image_data(gd_GIF *gif, int interlace), some like entries.prefix is error. It will be crash at line 370
entry = table->entries[entry.prefix];

My environment Windows7 SDL2-2.0.9

Transparent Background

The attached image 1 has a transparent background, though when loaded through the lib, its getting a blueish background. The attached image 2 has a transparent background and it getting a black color. Image 3 has a transparent background and it getting white.

I'm thinking they should all be black.

image 1:
test2

image 2:
test1

image 3:
test3

Embed alpha value to `gif->canvas`

Hello, I am using this library to load GIFs to pass frames to SFML. As the title says, if the alpha value exists in gif->canvas, then I can just directly make SFML use the data within gif->canvas and avoid this intermediate step:

          auto color = gif->canvas;
          auto buf = frame_buf;
          for (int i = 0; i < gif->height; ++i) {
            for (int j = 0; j < gif->width; ++j, color += 3, buf += 4) {
              buf[0] = color[0];
              buf[1] = color[1];
              buf[2] = color[2];
              buf[3] = 255 * !gd_is_bgcolor(gif, color);
            }
          }

`example.c:(.text+0x13d): undefined reference to `SDL_Init'`

On Debian sid/unstable with libsdl2-dev 2.24.0+dfsg-1, I get:

$ git log --oneline --no-decorate -1
1dcbae1 Merge pull request #17 from MichielP1807/master
$ pkg-config --cflags --libs sdl2
-D_REENTRANT -I/usr/include/SDL2 -lSDL2
$ cc `pkg-config --cflags --libs sdl2` -o gifplay gifdec.c example.c
/usr/bin/ld: /tmp/ccxL4R2w.o: in function `main':
example.c:(.text+0x13d): undefined reference to `SDL_Init'
/usr/bin/ld: example.c:(.text+0x146): undefined reference to `SDL_GetError'
/usr/bin/ld: example.c:(.text+0x15d): undefined reference to `SDL_Log'
/usr/bin/ld: example.c:(.text+0x197): undefined reference to `SDL_CreateWindowAndRenderer'
/usr/bin/ld: example.c:(.text+0x1a0): undefined reference to `SDL_GetError'
/usr/bin/ld: example.c:(.text+0x1b7): undefined reference to `SDL_Log'
/usr/bin/ld: example.c:(.text+0x21f): undefined reference to `SDL_SetWindowTitle'
/usr/bin/ld: example.c:(.text+0x283): undefined reference to `SDL_SetRenderDrawColor'
/usr/bin/ld: example.c:(.text+0x28f): undefined reference to `SDL_RenderClear'
/usr/bin/ld: example.c:(.text+0x29b): undefined reference to `SDL_RenderPresent'
/usr/bin/ld: example.c:(.text+0x2d2): undefined reference to `SDL_CreateRGBSurface'
/usr/bin/ld: example.c:(.text+0x2e6): undefined reference to `SDL_GetError'
/usr/bin/ld: example.c:(.text+0x2fd): undefined reference to `SDL_Log'
/usr/bin/ld: example.c:(.text+0x373): undefined reference to `SDL_PollEvent'
/usr/bin/ld: example.c:(.text+0x397): undefined reference to `SDL_Delay'
/usr/bin/ld: example.c:(.text+0x3a1): undefined reference to `SDL_GetTicks'
/usr/bin/ld: example.c:(.text+0x3c9): undefined reference to `SDL_LockSurface'
/usr/bin/ld: example.c:(.text+0x449): undefined reference to `SDL_MapRGB'
/usr/bin/ld: example.c:(.text+0x487): undefined reference to `SDL_MapRGB'
/usr/bin/ld: example.c:(.text+0x4ae): undefined reference to `SDL_MapRGB'
/usr/bin/ld: example.c:(.text+0x52a): undefined reference to `SDL_UnlockSurface'
/usr/bin/ld: example.c:(.text+0x53d): undefined reference to `SDL_CreateTextureFromSurface'
/usr/bin/ld: example.c:(.text+0x55b): undefined reference to `SDL_RenderCopy'
/usr/bin/ld: example.c:(.text+0x567): undefined reference to `SDL_RenderPresent'
/usr/bin/ld: example.c:(.text+0x573): undefined reference to `SDL_DestroyTexture'
/usr/bin/ld: example.c:(.text+0x578): undefined reference to `SDL_GetTicks'
/usr/bin/ld: example.c:(.text+0x5bd): undefined reference to `SDL_Delay'
/usr/bin/ld: example.c:(.text+0x5e8): undefined reference to `SDL_FreeSurface'
/usr/bin/ld: example.c:(.text+0x5f4): undefined reference to `SDL_DestroyRenderer'
/usr/bin/ld: example.c:(.text+0x600): undefined reference to `SDL_DestroyWindow'
/usr/bin/ld: example.c:(.text+0x605): undefined reference to `SDL_Quit'
collect2: error: ld returned 1 exit status

"gd_get_frame" function takes too long to execute

The gd_get_frame function takes more than one second to finish execution, which is considerably slow compared to other GIF decoders and nearly unusable in a runtime where performance is a key point.

gifdec/gifdec.c

Lines 464 to 482 in 54ab6c8

int
gd_get_frame(gd_GIF *gif)
{
char sep;
dispose(gif);
read(gif->fd, &sep, 1);
while (sep != ',') {
if (sep == ';')
return 0;
if (sep == '!')
read_ext(gif);
else return -1;
read(gif->fd, &sep, 1);
}
if (read_image(gif) == -1)
return -1;
return 1;
}

GIF used:
ez

Rendering with gd_is_bgcolor is inheritly flawed

Thank you for this lib! Appreciate the work.
However, rendering a frame to its RGB colors, and then using gd_is_bgcolor is inheritly flawed. It's not at all impossible that the bgcolor is set to a "color" that also appears elsewhere in the palette. gd_is_bgcolor will mark those non-transparent pixels as bg colors incorrectly.

gd_render_frame(gif, buffer);
    color = buffer;
    for (y = 0; y < gif->height; y++) {
        for (x = 0; x < gif->width; x++) {
            if (gd_is_bgcolor(gif, color)) // will return true for non-transparent similarly colored pixels as well
                transparent_pixel(x, y);
            else
                opaque_pixel(x, y, color);
            color += 3;
        }
    }

The solution is to fill the "render" buffer not with 3-byte RGB colors, but with 1-byte indices instead, and then check each index against the background index instead. Just pointing this out for other people, in case they run into the same problem as me.

Halt in read_image_data after some frame

Hi,

Thank you for this great library. We are using it in LVGL as an external library. See lv_lib_gif.

There we use a slightly modified version of your lib and noticed that it freezes with a gif.

I reproduced the issue with your original library too:

  gd_GIF * g = gd_open_gif("./a.gif");

  uint8_t buf[1024 * 1024];

  for(int i = 0; i < 50; i++) {
      int ret = gd_get_frame(g);
      printf("i: %d, ret: %d\n", i);
      gd_render_frame(g, buf);
  }

The output is:

i: 0, ret: 0
i: 1, ret: 0
i: 2, ret: 0
i: 3, ret: 0
i: 4, ret: 0
i: 5, ret: 0
i: 6, ret: 0
i: 7, ret: 0
i: 8, ret: 0
i: 9, ret: 0
i: 10, ret: 0
i: 11, ret: 0

The debugger says it spins the while(1) of read_image_data.

We use this image:
a

Do you have any ideas about what could be the issue?

Portion of previous frame erroneously appearing over current frame

I am processing a GIF file using gifdec. In a certain GIF I have made, when decoded using gifdec, the 3rd frame of the GIF erroneously shows a portion of the 2nd frame.

I have made a GIF which replicates this issue. The GIF is exported using Aseprite.
bg

This is how the 3rd frame appears when decoded using gifdec. It is supposed to appear as a solid color.
image

It's likely that the incorrect behaviour is related to the GIF's frame optimization, it seems like the portion of the image which is showing up as the 2nd frame should actually be showing as the 1st frame, as that portion of the 1st frame is the same as that same portion in the 3rd frame.
This may be due to an incorrect implementation of frame disposal, but I don't know enough about the GIF format though to be able to say for certain that this is the cause.

I am accessing the image data using gif->frame, because my use case requires reading indexed image data from the GIF. If this is incorrect, please let me know.

Potentially undefined variables

Compiler warnings

When compiling with gcc -Wall -O3, the compiler gives quite a few warnings. A lot of these consist of the fact that the return value of read() is often ignored, which is probably not really a problem. There are also some warnings about potentially undefined variables:

  • The fact that str_len could be uninitialized is probably a false positive since I think key starts out as equal to clear:
./gifdec.c:369:45: warning: ‘str_len’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  369 |             ret = add_entry(&table, str_len + 1, key, entry.suffix);
  • I'm not quite sure what causes the following warning about entry.suffix:
./gifdec.c:271:37: warning: ‘entry.suffix’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  271 |     table->entries[table->nentries] = (Entry) {length, prefix, suffix};
  • table_is_full could probably be initialized to 0:
./gifdec.c:368:19: warning: ‘table_is_full’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  368 |         } else if (!table_is_full) {

Valgrind warnings

When fuzzing with AFL, we found a couple of gifs that crash the library. When analyzing these crashes with Valgrind, we get warnings for conditional jumps or moves depending on uninitialized values and also the usage of uninitialized values.

Here are two gifs that currently crash the library:

  • segfault.gif results in a Segmentation fault (core dumped) crash
  • double_free_or_corruption.gif results in a double free or corruption (out) Aborted (core dumped) crash

(Right click and save image as to download, these are not proper working gifs so your browser probably won't display them.)

Using Valgrind with --track-origins=yes we get the following warnings for segfault.gif:

==8703== Conditional jump or move depends on uninitialised value(s)
==8703==    at 0x10A77A: read_image_data (gifdec.c:368)
==8703==    by 0x10A77A: read_image (gifdec.c:441)
==8703==    by 0x10A77A: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703==  Uninitialised value was created by a stack allocation
==8703==    at 0x109B81: gd_get_frame (gifdec.c:487)
==8703== Conditional jump or move depends on uninitialised value(s)
==8703==    at 0x10A7E1: read_image_data (gifdec.c:385)
==8703==    by 0x10A7E1: read_image (gifdec.c:441)
==8703==    by 0x10A7E1: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703==  Uninitialised value was created by a heap allocation
==8703==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==8703==    by 0x10A2D7: new_table (gifdec.c:245)
==8703==    by 0x10A2D7: read_image_data (gifdec.c:355)
==8703==    by 0x10A2D7: read_image (gifdec.c:441)
==8703==    by 0x10A2D7: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703== Conditional jump or move depends on uninitialised value(s)
==8703==    at 0x10AA8D: read_image_data (gifdec.c:363)
==8703==    by 0x10AA8D: read_image (gifdec.c:441)
==8703==    by 0x10AA8D: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703==  Uninitialised value was created by a heap allocation
==8703==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==8703==    by 0x10A2D7: new_table (gifdec.c:245)
==8703==    by 0x10A2D7: read_image_data (gifdec.c:355)
==8703==    by 0x10A2D7: read_image (gifdec.c:441)
==8703==    by 0x10A2D7: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703== Conditional jump or move depends on uninitialised value(s)
==8703==    at 0x10A8D1: interlaced_line_index (gifdec.c:315)
==8703==    by 0x10A8D1: read_image_data (gifdec.c:390)
==8703==    by 0x10A8D1: read_image (gifdec.c:441)
==8703==    by 0x10A8D1: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703==  Uninitialised value was created by a heap allocation
==8703==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==8703==    by 0x10A2D7: new_table (gifdec.c:245)
==8703==    by 0x10A2D7: read_image_data (gifdec.c:355)
==8703==    by 0x10A2D7: read_image (gifdec.c:441)
==8703==    by 0x10A2D7: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703== Use of uninitialised value of size 8
==8703==    at 0x10A868: read_image_data (gifdec.c:391)
==8703==    by 0x10A868: read_image (gifdec.c:441)
==8703==    by 0x10A868: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703==  Uninitialised value was created by a heap allocation
==8703==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==8703==    by 0x10A2D7: new_table (gifdec.c:245)
==8703==    by 0x10A2D7: read_image_data (gifdec.c:355)
==8703==    by 0x10A2D7: read_image (gifdec.c:441)
==8703==    by 0x10A2D7: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703== Conditional jump or move depends on uninitialised value(s)
==8703==    at 0x10AA71: read_image_data (gifdec.c:398)
==8703==    by 0x10AA71: read_image (gifdec.c:441)
==8703==    by 0x10AA71: gd_get_frame (gifdec.c:500)
==8703==    by 0x109494: main (test.c:45)
==8703==  Uninitialised value was created by a stack allocation
==8703==    at 0x109B81: gd_get_frame (gifdec.c:487)

And for double_free_or_corruption.gif we get some of the same warnings as above, but also:

==8729== Use of uninitialised value of size 8
==8729==    at 0x109692: memcpy (string_fortified.h:34)
==8729==    by 0x109692: render_frame_rect (gifdec.c:455)
==8729==    by 0x109423: main (test.c:53)
==8729==  Uninitialised value was created by a heap allocation
==8729==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==8729==    by 0x10A2D7: new_table (gifdec.c:245)
==8729==    by 0x10A2D7: read_image_data (gifdec.c:355)
==8729==    by 0x10A2D7: read_image (gifdec.c:441)
==8729==    by 0x10A2D7: gd_get_frame (gifdec.c:500)
==8729==    by 0x109402: main (test.c:45)
==8729== Conditional jump or move depends on uninitialised value(s)
==8729==    at 0x10968C: render_frame_rect (gifdec.c:454)
==8729==    by 0x109423: main (test.c:53)
==8729==  Uninitialised value was created by a heap allocation
==8729==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==8729==    by 0x10A2D7: new_table (gifdec.c:245)
==8729==    by 0x10A2D7: read_image_data (gifdec.c:355)
==8729==    by 0x10A2D7: read_image (gifdec.c:441)
==8729==    by 0x10A2D7: gd_get_frame (gifdec.c:500)
==8729==    by 0x109402: main (test.c:45)

I haven't looked into what causes these warnings/errors, but it turns out that it possible to crash the library with corrupted gifs because of potentially uninitialized variables.

Lack of license

Greetings,

I would like to use your code in my project, but as this page suggests it's better to ask the owner to add a license instead of using unlicensed code.

Could you please then add a license? (preferably MIT 😄 )

Problem with a particular gif

Hi,

Thanks for sharing this great piece of work!

This gif is not displayed correctly: the palette is incorrect and also the image is distorted.

Can you have a look at it?
10x

Buffer overflows (found with AFL)

Thanks for making this great library! It was fun learning a bit about how gifs work!

We fuzzed this library for a school project and we found quite a few buffer overflow vulnerabilities and some integer overflow vulnerabilities. These can cause a variety of different errors, from segmentation fault to all kinds of free and malloc based memory errors. There also were quite a few potentially uninitialized values. We made an attempt at fixing the buffer overflows and integer overflows, but we were not sure how to fix all the potentially uninitialized values that can still crash this library with certain input gifs.

  • One common issue that caused buffer overflows, is that frames can go out of bounds within the gif. If the gif->fx, gif->fy, gif->fw, or gif->fh are too large, then we will be reading and writing outside of the gif buffer. To fix this, we have changed some of the for loops to make sure that the x and y coordinates do not go outside of the width and height of the gif.
  • Another issue is an integer overflow when the width and height of a gif are very large. The calloc(1, sizeof(*gif) + 4 * width * height) that allocates memory for the gif buffer will sometimes allocated not enough memory because the value of sizeof(*gif) + 4 * width * height can overflow. In our attempt to fix this, we have separated this calloc into 3 separate calloc's: one for the gif struct, one for the gif->canvas, and one for the gif->frame.
  • In the add_entry function, there can be a buffer overflow when table->nentries is not set properly. The value of table->nentries is computed either (1 << key_size) + 2 or (1 << (key_size - 1)) + 2. We added some extra checks to make sure that the key_size is not too large, since the computations overflow when key_size is larger or equal to 31 or 32 respectively. We are not entirely sure that this is indeed a good assumption that key_size should be smaller than 31 or 32 at these places, so if you have any comments, please let us know!

interlaced GIF

Hi!
Thanks for making this, I was looking for a small and simple GIF decoder and this one seems to work fine...

... except I don't think it handles interlaced GIFs correctly. Here's an example (the first frame is interlaced) :

animhorse

Missing license

Hi,
Great piece of software but can i use it in my project ?
You should tell people under what license this code is released.
Without any license i have no right to use your code !

See here:
https://choosealicense.com/

If you just don't care and want to let everyone just do whatever they want with it, i suggest you choose an MIT license.
Go here https://choosealicense.com/licenses/mit/ and copy / paste the license text in the header of each c and h file, that's all.
(This involves defining a copyright with your name)

Best regards

Francois

questions

if i just want to read the gif, show it on the matrix and repeat, i would use this and uncomment the other ones?

/* Read image.
 * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
static int
read_image(gd_GIF *gif)
{
    uint8_t fisrz;
    int interlace;

    /* Image Descriptor. */
    gif->fx = read_num(gif->fd);
    gif->fy = read_num(gif->fd);
    gif->fw = read_num(gif->fd);
    gif->fh = read_num(gif->fd);
    read(gif->fd, &fisrz, 1);
    interlace = fisrz & 0x40;
    /* Ignore Sort Flag. */
    /* Local Color Table? */
    if (fisrz & 0x80) {
        /* Read LCT */
        gif->lct.size = 1 << ((fisrz & 0x07) + 1);
        read(gif->fd, gif->lct.colors, 3 * gif->lct.size);
and then code 3 buttons to pause,go to the next one and go back one
        gif->palette = &gif->lct;
    } else
        gif->palette = &gif->gct;
    /* Image Data. */
    return read_image_data(gif, interlace);
}

Clang compatibility

gifdec errors on compile with Windows 10 using the latest clang on example.c.

Seemingly it's missing a library not stated in the readme:
error2

The above all works fine on my Debian install but not Windows.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.