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:

  1. Property Type: A 32-bit integer identifying the property (e.g., PROP_COLORMAP, PROP_COMPRESSION, PROP_GUIDES, PROP_PARASITES).
  2. Payload Size: A 32-bit (or 64-bit in newer versions) integer specifying the length of the property data in bytes.
  3. 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) and GIMP_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.