AnimatedGIF decodes GIFs one scanline at a time so a microcontroller never holds a framebuffer
An optimized GIF decoder suitable for microcontrollers and PCs
At a glance
- What is it?
- AnimatedGIF is a C99 GIF decoder written to run on an MCU with as little as 24K of RAM: it hands you one line of output at a time through a callback, allocates nothing dynamically, and has a Turbo mode that trades 32K more RAM for two to thirty times the decode speed. The same code is fast on a desktop, where the author says it beats libgif.
- Who is it for?
- Adopt AnimatedGIF if you are putting a GIF on a microcontroller or a bare metal target with a small framebuffer, because the callback-per-line design means the decoded image never has to exist in RAM as a whole, and the no-malloc rule makes it buildable on a minimal system. Do not adopt it if you need a full-featured GIF library on a desktop, since the author positions it as faster than libgif for decoding but the repository is not a general image library.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 111 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why this decoder exists: a GIF player for any MCU
AnimatedGIF is described as an optimized GIF decoder suitable for microcontrollers and PCs, and the README tells the story of why it was written.
The author started working with image and video files around 1989 and soon turned the interest into a Document Imaging product based on his own imaging library. He sold that business in 1997 but kept finding uses for the imaging code in other projects such as retro gaming. When he went looking for a good GIF player for Arduino, he only found Adafruit's library, and it only runs on their ATSAMD51 boards. He thought it would be possible to use the old code to create a universal GIF player that could run on any MCU or SoC with at least 24K of RAM, so he started modifying the old GIF code for that purpose. The latest focus of the project is both raw code speed and features that allow it to run well on microcontrollers.
The MCU accommodations are the design. The original idea of the project was to bring efficient GIF decoding to MCUs with insufficient memory to hold the entire framebuffer. It grew to include design features meant to accelerate SPI LCD output. The premise is that for most images, each line can be decoded and sent to the display, hopefully using DMA, while the next line is being decoded. This allows the SPI transmit time to essentially vanish and greatly reduces the amount of memory required.
The other goal was to not dynamically allocate and free memory, and all buffers are managed outside of the library. That is what lets the code compile as C99 with no external dependencies beyond the basic clib and string functions, and the feature list spells out the consequences: does not use dynamic memory, malloc, free, new or delete, so it is easy to build for a minimal bare metal system, and the C99 code doing the heavy lifting is completely portable.
The C++ class and callback design on top of that is for application use, and the README says a simple C++ class and callback design allows you to easily add GIF support to any application.
The library is Apache-2.0 licensed, written in C, with the default branch master and the last push on 2026-07-03. The recent releases are 2.2.0 from 2025-02-25, 2.1.1 from 2024-07-09 and 2.1.0 from 2024-03-08, and the last one added 1-bit cooked output while the one before it fixed a loop count.
The three output modes, and what each one costs in RAM
The newest version brings much more speed to all modes of operation plus a new way to decode, Turbo mode, which trades more memory for more speed. The author took another look at the decoder and found some creative ways of speeding it up.
Turbo mode uses the output image as the dictionary. It needs another 32K of RAM and can accelerate the decoding by 2 to 30 times depending on the target system and image. That is a large range, which tells you the speed-up is a property of the specific data rather than a fixed multiplier.
The other two modes are older and cheaper. The library can emit 32-bpp output, and the GIFDraw callback is now optional, which means a caller who wants raw pixels can skip the callback layer. Then there is the option to request COOKED output, which means that the library will handle merging new frames onto the canvas and the GIFDraw callback gets pixels ready for display.
That distinction is the subtle one. In the raw mode you receive the decoded pixels of the current frame and you are responsible for compositing it onto whatever canvas you keep. In cooked mode the library does the merging, which is the difference between a GIF that displays correctly with transparency and one that does not.
The README is blunt about the tradeoff, in a note that appears as a diff in the source:
- N.B. Using a minimum of RAM on an MCU (not holding on to the fully rendered canvas) presents
- limitations on speed and what files will display correctly. If you're using a SPI LCD and manage
- the palette translation yourself, your code will update the display slower when there are
- alternating areas of transparent and opaque pixels because the LCD must be sent windowing
- commands in between the runs of pixels. If you instead choose to let AnimatedGIF handle
- the palette translation (COOKED mode), you run into a problem with GIF files that have
- local color palettes. They will not display correctly unless you keep a copy of the
- entire canvas in the final output pixel type (e.g. Width * Height * 3-bytes per pixel).So both branches of the decision cost something. Managing the palette yourself costs speed on images with alternating transparency. Letting the library do it costs a full copy of the canvas in the output pixel format, which for a 320 by 240 image at three bytes per pixel is already 230K, and for an MCU with 24K of RAM it rules the option out entirely.
Certain disposal options also will not render correctly in the streaming arrangement, and images with lots of alternating transparent and opaque pixels will slow down the SPI output due to the mode switching.
The GIFDraw callback, and the honest warning about it
The section headed It's Easy Until It's Not is the most useful thing in the README, because it tells you what will actually be hard.
The README asks you to look through the example code and the wiki for information on how best to get things working for your specific setup. If you have lots of spare memory, the code can do a lot of the work for you, but if your system is more constrained it can take more effort to get all of the pieces working well together.
The biggest challenge is usually the GIFDraw callback function. It sends you one line of output at a time, but also includes extra info to help with SPI displays.
That callback is the entire interface of the library, and the reason it is hard is that it has to do two jobs at once. It has to hand you a run of pixels that belong to the current line, and it has to give you the information the display needs to know how to send them, which for an SPI LCD means the windowing commands, the palette indices if you are doing the translation yourself, and the ordering.
The consequence of that design is visible in the example list. There are twenty-three example directories, and they are named after the platform and the mode rather than after a feature: ESP32-LGFX-SDCard-GifPlayer, ESP32_LEDMatrix_I2S, NeoPixel_Player, TFT_eSPI_memory, TinyPico_Display_GIF, adafruit_gfx_memory, adafruit_gfx_sdcard, best_practices_example, big_mem_demo, bitbank_lcd_library, cyd_cooked_demo, esp32s3_simd_demo, ez_gif_player, function_test, gif_animated_digits, gif_benchmark, gif_clock, gif_from_spi_flash, gif_transparency_demo, oled_gif_demo, perf_explained, play_all_sd_files, turbo_t_qt_example and two_instances.
The names say a lot about what the author expects people to build against. There are multiple display libraries, both memory and SD card sources, a cooked demo for a particular board, a transparency demo, a benchmark, a best practices example, a big memory demo and a Turbo example. Those are the combinations that are hard, and the author has written one example for each instead of writing a framework that hides the differences.
Getting the GIF data in, and the awkward step of embedding it
The README describes where the image data comes from: GIF image data can come from memory, FLASH or RAM, SDCard or any media you provide, and GIF files can be any length, for example hundreds of megabytes.
The acquiring section then describes something unusual. The images provided in the test_images folder have been turned into C code. Each byte is now in the form 0xAB so that it can be compiled into your program and stored in FLASH memory alongside your other code. The author wrote a command called image_to_c to convert a binary file into this type of text, and if you use another tool you have to add a const modifier in front of the GIF data array.
That is a solve-the-toolchain-problem move rather than a design decision. On a microcontroller with no filesystem and no SD card, the GIF has to be in the firmware image, and the only way to get it there is as a compiled array. The const requirement is not cosmetic either, since without it the array lands in RAM instead of FLASH on most embedded targets, which for a multi-megabyte GIF is the difference between working and not.
The library directory is called src/ and there is a library.properties file at the root, which is the Arduino library manifest, so the library drops into an Arduino IDE project as-is. The MacOS/ and linux/ directories hold native builds for testing on a desktop, and there is a test_images/ folder holding the files the performance chart was measured from.
The examples cover the realistic sources of data: from SPI flash, from an SD card, from memory, and one that plays all SD files. Combined with the callback design, that means the data source is decoupled from the decoder, which is what lets the same decoder sit behind an SD card reader, a serial link or a compiled array.
Where AnimatedGIF is the wrong choice
Three limits, and the first is about the scope of the format it supports.
The first is that this is a GIF decoder, and GIF is a format with genuinely awkward features that different decoders handle differently. The README is explicit that certain disposal options will not render correctly in the streaming arrangement, and that files with local color palettes will not display correctly in cooked mode unless you keep a copy of the entire canvas in the final output pixel type. So there is a class of GIF files where this decoder, in one mode or another, needs more memory than an MCU has, and there is a class where it renders them differently from a desktop viewer. If your content comes from a known source with a known encoding profile, that is survivable. If your content comes from anywhere on the web, you should expect some files to look wrong.
The second is the trade the README explicitly warns about: this is easy until it is not. The GIFDraw callback is the biggest challenge, and for a constrained system it takes real effort to get all the pieces working well together. That is a maintenance commitment that comes with the memory saving. A desktop application has RAM to spare, so the library will do the work for you, and the same library on an MCU becomes a project.
The third is that the performance claims are about decoding, not about display. The chart shows the total time to decode an 8-frame sequence from the test_images folder, and the decoding speed of your particular image depends on the complexity, how much compressed data, and whether and how transparent pixels are used. Small runs of transparent pixels will interfere with the performance of displaying the image on an SPI LCD. The image in the chart does not use transparency, so the time is purely for decoding the data.
That last qualification is the important one, and it is easy to miss. The headline numbers are for images without transparency, which is the easy case. On a device with an SPI LCD, the display update time, not the decode time, is likely to be your bottleneck, and the library says so plainly: the main limitation will be how fast you can copy the pixels to the display.
The alternative approach for a desktop application is libgif, or an image library like stb_image with its own GIF support, where the whole frame is decoded into memory and you draw from it. The difference in approach is that a full-frame decoder needs the framebuffer but has none of the streaming complications, no per-line callback to write, no disposal method edge cases in the streaming path, and no separate cooked mode. For a device with a real framebuffer, that is the simpler system. For a device with 24K of RAM and an SPI display, it is not an option at all, and that is the case this library exists for.
Editorial conclusion
Adopt AnimatedGIF if you are putting a GIF on a microcontroller or a bare metal target with a small framebuffer, because the callback-per-line design means the decoded image never has to exist in RAM as a whole, and the no-malloc rule makes it buildable on a minimal system. Do not adopt it if you need a full-featured GIF library on a desktop, since the author positions it as faster than libgif for decoding but the repository is not a general image library. Verify first that your target has at least 24K of RAM as the README states, that you understand which disposal methods and transparency patterns render correctly in the streaming mode, and that you choose between the plain mode, the cooked mode that handles frame merging for you, and the Turbo mode with its extra 32K of RAM, since the README is explicit that the fastest option is not the smallest one.
Frequently asked questions
What is AnimatedGIF and what is it for?
It is an optimized GIF decoder in C99 with no external dependencies beyond the basic clib and string functions, written for MCUs and SoCs with as little as 24K of RAM. It hands decoded output to the caller one line at a time through the GIFDraw callback and does not use dynamic memory, so it suits bare metal systems.
What is Turbo mode in AnimatedGIF and what does it cost?
Turbo mode is a decode mode that uses the output image as the dictionary. It needs another 32K of RAM and can accelerate decoding by 2 to 30 times depending on the target system and the image.
What is the difference between raw and COOKED output in AnimatedGIF?
In raw output the GIFDraw callback receives decoded pixels and you handle palette translation and compositing. In COOKED output the library handles merging new frames onto the canvas and gives you pixels ready for display, but GIFs with local color palettes will not display correctly unless you keep a copy of the entire canvas in the output pixel type.
How do I get GIF data into an AnimatedGIF program?
The data can come from memory, FLASH or RAM, an SD card, or any media you provide, and files can be any length. The bundled test images were converted to C code with the author's image_to_c command so they can be compiled into FLASH, and if you use another tool you must add a const modifier in front of the GIF data array.
How fast is AnimatedGIF compared to libgif?
The README says the code can be used on PC class devices and will perform far better than libgif, with the optimizations helping on MCU class devices as well as x86, Arm and RISC-V Linux and PC devices. The chart measures the total time to decode an 8-frame sequence, and the speed depends on image complexity and on transparent pixel usage.
What are the limitations of AnimatedGIF on a microcontroller?
The README warns that using a minimum of RAM on an MCU, not holding on to the fully rendered canvas, presents limitations on speed and on what files will display correctly. Certain disposal options will not render correctly, images with lots of alternating transparent and opaque pixels slow down SPI output due to mode switching, and the biggest challenge is usually writing the GIFDraw callback correctly.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bitbank2-animatedgif)Was this useful?