A GIF file is not a grid of pixels like a bitmap. It is a linear sequence of blocks, read one after another by the decoder until a terminating byte marks the end.
Overall Structure
Header
Logical Screen Descriptor
Global Color Table (optional)
┌─ Graphic Control Extension (optional)
├─ Image Descriptor
├─ Local Color Table (optional)
└─ Image Data (LZW-compressed)
... repeated per frame ...
Trailer
Header (6 bytes)
Plain ASCII text identifying the file and version:
GIF87a— original 1987 spec, no animation supportGIF89a— 1989 spec, adds animation, transparency, comment and text blocks
Almost all GIFs today use GIF89a, even static ones.
Logical Screen Descriptor (7 bytes)
Defines the canvas all frames are drawn on.
| Field | Size | Description |
|---|---|---|
| Canvas Width | 2 bytes | Width in pixels |
| Canvas Height | 2 bytes | Height in pixels |
| Packed Byte | 1 byte | Flags, see below |
| Background Color Index | 1 byte | Index into global color table |
| Pixel Aspect Ratio | 1 byte | Rarely used, usually 0 |
Packed Byte
Bit: 7 6 5 4 3 2 1 0
GCT Color Sort Size of
Flag Resolution Flag Color Table
- Global Color Table Flag (1 bit): whether a global color table follows
- Color Resolution (3 bits): bit depth of the source image before palette reduction; informational only
- Sort Flag (1 bit): whether the color table is sorted by frequency; mostly ignored by decoders
- Size of Global Color Table (3 bits): number of colors, calculated as 2^(value+1)
| Value | Colors |
|---|---|
| 0 | 2 |
| 3 | 16 |
| 7 | 256 (max) |
This 3-bit field is why GIF is capped at 256 colors.
Color Table
GIF uses indexed color. A pixel stores an index (0–255) into a palette, not an RGB value directly:
Palette = [R,G,B, R,G,B, R,G,B, ...]
Index0 Index1 Index2 ...
- Global Color Table (GCT): default palette for the whole file
- Local Color Table (LCT): optional per-frame override
Extension Blocks
Prefixed with 0x21.
Graphic Control Extension
| Field | Description |
|---|---|
| Disposal Method | What to do with the frame before the next is drawn (leave, clear to background, restore previous) |
| Transparency Flag | Whether a palette index is treated as transparent |
| Delay Time | Display duration in 1/100 sec |
| Transparent Color Index | Which palette index is transparent |
Application Extension
Used for the (unofficial but universal) Netscape loop count extension, defining how many times the animation repeats (0 = infinite).
Image Descriptor (per frame)
Prefixed with 0x2C. Defines position and size of a single frame relative to the canvas.
| Field | Size | Description |
|---|---|---|
| Left Position | 2 bytes | X offset on canvas |
| Top Position | 2 bytes | Y offset on canvas |
| Width | 2 bytes | Frame width |
| Height | 2 bytes | Frame height |
| Packed Byte | 1 byte | Local Color Table Flag, Interlace Flag, Sort Flag, Size of LCT |
A frame does not need to cover the full canvas — only the changed region can be encoded, leaving the rest untouched.
Image Data
- LZW Minimum Code Size (1 byte)
- Sub-blocks: LZW-compressed data split into chunks of up to 255 bytes, each preceded by a length byte; a zero-length block signals the end
LZW compression is mandatory in the spec — there is no uncompressed mode.
After decompression, the result is a set of palette indices per pixel, per frame — conceptually a 3D array (frame × row × column) of indices. This structure only exists post-decompression; on disk it is a compressed, block-segmented byte stream.
Trailer (1 byte)
0x3B (ASCII ;). Marks end of file. No file size field or content index — decoding proceeds sequentially until this byte.
Block Type Reference
| Byte | Meaning |
|---|---|
0x21 | Extension Block |
0x21 0xF9 | Graphic Control Extension |
0x21 0xFE | Comment Extension |
0x21 0x01 | Plain Text Extension |
0x21 0xFF | Application Extension |
0x2C | Image Descriptor (new frame) |
0x3B | Trailer |