How GIMP Saves Project State to Binary XCF
This article explores how the GNU Image Manipulation Program (GIMP) serializes complex project states into its native binary XCF format. It breaks down the internal file layout, the role of property lists, and how GIMP uses extensible "parasite" data structures to encapsulate custom tool parameters and environment states without corrupting core image data or breaking backward compatibility.
The Core Structure of the XCF Binary Format
The XCF format is a structured binary container designed to map
directly to GIMP's in-memory image hierarchy. An XCF file begins with a
14-byte header containing a magic signature string (e.g.,
gimp xcf file or gimp xcf v014), which
establishes the format version and determines whether offsets are read
as 32-bit or 64-bit integers.
Immediately following the header, the format writes the basic canvas attributes:
- Canvas width and height in pixels
- Base color mode (RGB, Grayscale, or Indexed)
- Precision and channel encoding formats (in modern versions)
Rather than storing data in arbitrary streams, GIMP organizes the remaining project metadata and hierarchy using sequential property lists and absolute file offset pointers.
The Property List Architecture
Before writing raw pixel hierarchies, layers, or channels, GIMP writes a serialized linked sequence of properties associated with the image canvas. Each property in an XCF file follows a standard type-length-value (TLV) structure:
- Property Type: A 32-bit integer identifying the
property (e.g.,
PROP_COLORMAP,PROP_COMPRESSION,PROP_GUIDES,PROP_PARASITES). - Payload Size: A 32-bit (or 64-bit in newer versions) integer specifying the length of the property data in bytes.
- Payload Data: The raw binary payload defined by the specific property type.
The property list continues sequentially until it encounters a
terminating PROP_END marker (a property type identifier of
0 with a payload length of 0). This
architecture allows the parser to scan properties predictably and safely
skip unhandled or newer property definitions by utilizing the payload
size offset.
Retaining Tool Settings via the Parasite Subsystem
Standard XCF properties handle fixed image traits like resolution, unit scale, and color profiles. To save arbitrary runtime states—such as active tool configurations, custom brush dynamics, plug-in states, and project-specific contexts—without requiring a schema change for every new feature, GIMP employs an abstraction layer known as Parasites.
A parasite is an arbitrary, named data block managed by the
GimpParasite structure. Within the XCF format, parasites
are bundled into the PROP_PARASITES property chunk.
Each serialized parasite consists of:
- Name: A null-terminated UTF-8 string identifying the data owner (for example, metadata payloads, plug-in settings, or tool options).
- Flags: A 32-bit bitmask determining persistence
rules, such as
GIMP_PARASITE_PERSISTENT(instructing the serializer to write it to disk) andGIMP_PARASITE_UNDOABLE(tracking changes through the undo buffer). - Size: A 32-bit unsigned integer denoting the payload size.
- Data: A contiguous binary buffer containing the serialized state.
When custom tool presets or context variables must be tied to a
project, GIMP serializes these configurations into key-value strings or
structured binary blobs. These blobs are packaged as persistent image
parasites. When the serializer encounters them during project export,
they are written directly into the PROP_PARASITES block of
the image or layer property list.
Pointers and Layer Hierarchies
Once the primary image properties and parasites are written, the file outputs offset tables:
- An array of absolute file offsets pointing to each layer's serialization block.
- An array of absolute file offsets pointing to channel structures.
Each layer and channel record contains its own isolated property
list—also terminated by PROP_END—allowing layers to store
their own independent parasite payloads, blend modes, masks, and
visibility flags. The actual pixel data is stored downstream in tile
hierarchies (typically 64x64 pixel blocks), compressed via algorithms
such as RLE or zlib, referenced directly by tile offset pointers.
Backward Compatibility and Fault Tolerance
Because custom tool configurations reside within the parasite subsystem rather than hardcoded binary structs, older or minimal XCF parsers can read files containing modern tool settings. If a parser encounters a parasite tag it does not natively implement, it preserves or skips the binary payload based on its flags without misaligning the file read pointers. This mechanism guarantees that tool states remain intact across save-and-load cycles without disrupting core raster rendering.