GIF Parser: Extension Block vs Image Separator
This article explains how a Graphics Interchange Format (GIF) parser distinguishes between an extension block marker and an image separator byte. It covers the stream-level sentinel byte values defined in the GIF specifications (GIF87a and GIF89a), the sequential state machine used during parsing, and how the parser maintains byte alignment across variable-length sub-blocks to prevent misinterpreting data payloads as block markers.
A GIF parser distinguishes between an extension block and an image block by reading a single-byte sentinel value at the root level of the data stream. After reading the file header, the Logical Screen Descriptor, and any optional Global Color Table, the parser enters a loop expecting one of three valid structural markers:
0x21(ASCII!): Extension Introducer. This value explicitly signals the start of an extension block (such as Graphic Control, Plain Text, Application, or Comment extensions).0x2C(ASCII,): Image Separator. This value explicitly signals the beginning of a Table-Based Image Descriptor.0x3B(ASCII;): Trailer. This value indicates the end of the GIF data stream.
Because 0x21 and 0x2C are distinct binary
values, the parser identifies the incoming block type through a
straightforward conditional check on this single byte.
State Tracking and Stream Synchronization
Distinguishing these markers relies on parser state synchronization. The parser only evaluates sentinel bytes when it is outside of any encapsulated data block. Once a sentinel is encountered, the parser follows specific structural rules defined for that block before looking for the next sentinel:
When 0x21
(Extension Introducer) Is Read:
- The parser reads the very next byte, which is the Extension
Label (for example,
0xF9for Graphic Control or0xFFfor Application). - The parser then processes the extension payload, which is structured as a series of data sub-blocks. Each sub-block begins with a length byte (1 to 255) specifying the size of that chunk.
- The parser consumes data chunks sequentially until it encounters a
Block Terminator byte of value
0x00(a sub-block of length zero). - Once the terminator is read, the extension is complete, and the parser returns to the root state, ready to read the next marker byte.
When 0x2C (Image
Separator) Is Read:
- The parser reads the fixed 9-byte Image Descriptor containing boundary coordinates (Left, Top, Width, Height) and packed field flags.
- If the packed field indicates a Local Color Table, the parser reads the specified number of RGB palette bytes.
- The parser reads one byte representing the LZW Minimum Code Size.
- The parser then reads the image raster data, which is also organized
as length-prefixed data sub-blocks ending with a
0x00Block Terminator. - Once the zero-byte terminator is consumed, the image block is fully processed, returning the parser to the root state to look for the next marker.
By enforcing length-based sub-block encapsulation, image data and
extension metadata—even if they contain the raw byte values
0x21 or 0x2C—are skipped as raw payload. The
parser only interprets 0x21 and 0x2C as
structural indicators when it has cleanly exited the previous block's
terminating sequence.