The Anatomy of a GIF

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 support
  • GIF89a — 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.

FieldSizeDescription
Canvas Width2 bytesWidth in pixels
Canvas Height2 bytesHeight in pixels
Packed Byte1 byteFlags, see below
Background Color Index1 byteIndex into global color table
Pixel Aspect Ratio1 byteRarely 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)
ValueColors
02
316
7256 (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

FieldDescription
Disposal MethodWhat to do with the frame before the next is drawn (leave, clear to background, restore previous)
Transparency FlagWhether a palette index is treated as transparent
Delay TimeDisplay duration in 1/100 sec
Transparent Color IndexWhich 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.

FieldSizeDescription
Left Position2 bytesX offset on canvas
Top Position2 bytesY offset on canvas
Width2 bytesFrame width
Height2 bytesFrame height
Packed Byte1 byteLocal 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

  1. LZW Minimum Code Size (1 byte)
  2. 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

ByteMeaning
0x21Extension Block
0x21 0xF9Graphic Control Extension
0x21 0xFEComment Extension
0x21 0x01Plain Text Extension
0x21 0xFFApplication Extension
0x2CImage Descriptor (new frame)
0x3BTrailer