Main Content

Minimal GIF Decoder

This is a GIF image decoder designed to allow GIF images to be read and displayed by a small microcontroller

It’s useful if you want to decode GIF images from the flash memory on the processor, or from an SD card, and display them on a TFT or OLED display. The Minimal GIF Decoder takes about 1K bytes of program memory, and requires just over 12K bytes of RAM, so it will run on any processor with at least 16K bytes of RAM. I used an AVR128DA28.

As a demonstration of the GIF encoder I’ve included a slide-show application that displays a sequence of different images read from the processor’s flash memory. I also give details of how to display GIF images from an SD card.

The GIF image format is ideal for storing images to be displayed on a small TFT or OLED display. It uses the LZW compression algorithm which provides efficient compression of many types of images, and the code to decode LZW-compressed images can be made relatively compact. It’s also well supported by image editors.

I needed a GIF display routine for a project and couldn’t find a GIF decoder aimed at microcontrollers with a relatively small amount of RAM, so I decided to try and write one. The result is a decoder that uses just over 12K bytes, and is therefore suitable for AVR processors with at least 16K bytes of RAM such as the AVR128DA28 or ATmega1284P. It will also run on 32-bit processors such as the ATSAMD21 and ATSAMD51, and I include an example of it running on the ATSAMD51-based Adafruit PyBadge.

These processors have plenty of flash, so you could store several compressed GIF images in flash and display them using the decoder, for a stand-alone slide-show project. Alternatively you can read GIF images from an SD card and display them.

LZW compression
The GIF format treats the image as a linear stream of pixel colour values. The LZW compression it uses works by finding a sequence of pixels it has already encountered, and it encodes each sequence as a variable-length code of from 3 to 12 bits. These codes are then output as a continuous stream of bits.

Decoding a GIF requires the decoder to divide the input stream into codes containing the correct number of bits. These codes are then looked up in a 4096-element table, to translate them into the appropriate sequence of one or more pixels represented by that code.

It would be very memory intensive if we had to store the complete pixel sequence corresponding to every code in the table. Fortunately, every sequence is equivalent to an earlier sequence, extended by the addition of one pixel. We can therefore represent the sequence as a pointer to the earlier sequence in the table, plus the additional pixel. Each entry in the lookup table therefore needs to store a 12-bit pointer to an earlier entry in the table, plus an 8-bit byte for the colour of the additional pixel in the sequence.

The clever thing about LZW compression is that the lookup table doesn’t need to be included with the GIF image, because it can be reconstructed dynamically as the code values are read in from the input stream. For a full description of how the GIF format works see the Wikipedia page [1]. I also got a lot of help from articles by Joshua Davies [2] [3] and Larry Bank [4].

Colour table
A GIF image can contain a colour table of up to 256 colours, so there also needs to be a 256-byte array to store this colour table. Each colour is defined by three bytes, giving the colour’s R, G, and B components. Since this GIF decoder is intended for displaying images on TFT displays with a 5-6-5 colour space, we can reduce each entry in the colour table to 16 bits.

Memory requirement
The total RAM requirement is therefore 4096 x 3 + 256 bytes, or just over 12Kbytes. There are ways of reducing the RAM requirements with a bit more programming, but to keep the decoder as simple as possible I’ve avoided these; see Further suggestions for details of how these could work.

The compression table and colour table are allocated as fixed arrays, and the program doesn’t use malloc for dynamic memory allocation.

This decoder doesn’t support: the older GIF87a format, animated GIFs, local colour tables, transparency, interlaced GIFs, or other extensions. If it encounters an unknown format it flashes an LED with an error code. However it should work with standard GIFs created by a range of image editors, and I’ve tested it with images from several editors.”

Link to article