Serif has not published the format, and little public reverse engineering exists.
What follows comes from two sources: Nick Beeuwsaert’s AFDesignLoad notes (2015, on
Affinity Designer 1 files, and largely guesswork by the author’s own account) and the
.afdesign signature in the PhotoRec file-recovery tool. All Affinity
programs (Photo, Designer, Publisher) share the container, so the same layout applies
to .afphoto. Nothing public describes how later versions, including
Affinity 2 and the 2025 Affinity app, may have changed it.
Header
Numbers are little-endian. Four-letter tags are stored as little-endian 32-bit
values, so their bytes appear reversed in the file: the tag Prsn appears
as nsrP.
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 4 | bytes | signature | 00 FF 4B 41. |
| 4 | 4 | u32 | version | Container version. |
| 8 | 4 | tag | Prsn | Bytes nsrP; PhotoRec requires them. |
| 12 | 4 | tag | #Inf | Start of the information block. |
| 16 | 8 | u64 | fat_offset | Offset of the file table (#FAT). |
| 24 | 8 | u64 | fat_length | End or length of the file table. |
| 32 | 8 | u64 | zlib_length | Length of the compressed data; PhotoRec uses it as the smallest possible file size. |
| 40 | 8 | unused | Unknown. | |
| 48 | 4 | u32 | creation | Creation time, a Unix timestamp. |
| 52 | 4 | unused | Zero. | |
| 56 | 8 | u64 | fat_entries | Number of file table entries. |
| 64 | 8 | u64 | fil_entries | Number of file entries. |
AFDesignLoad itself was unsure whether the header is 68 bytes or of variable length; PhotoRec reads it as this 72-byte structure.
File table
The container holds several internal files, listed in a table that starts with the
tag #FAT, with file entries marked #Fil; sections end with
FF FF FF FF. Each file entry is reported to hold an unknown 32-bit value,
a flag, the data offset, the uncompressed length, the stored length, a date, a
“compressed” flag, a 16-bit name length and the name. Compressed files use zlib.
The only internal name identified with confidence is doc.dat, the
document itself. Others have directory-like names such as d/a or
b/a.
doc.dat fields
The document is a tree of tagged fields. Tags reported so far, with how sure the notes are:
| Tag | Status | Contents |
|---|---|---|
Root | guess | Offset of the root node. |
Chld | partly known | Number of children. |
Desc | known | A 16-bit length and a name: the layer’s description. |
Visi | known | A boolean: visible. |
Opac | known | A float: opacity. |
FOpc | known | A float: fill opacity. |
Blnd | guess | Blend mode; layout unknown. |
SprB | partly known | 36 bytes with a double (usually zero), width and height; probably the size of the spread (canvas). |
Mrgn | guess | Four doubles: left, top, right and bottom margins. |
Rect | known | Four 32-bit integers: x, y, width, height. |
BmpW, BmpH | known | 32-bit bitmap width and height. |
Bitm | partly known | A flag and a 32-bit size: a bitmap. |
Frmt | partly known | A 32-bit value, thought to be the pixel format. |
Data | known | A 16-bit size and raw bytes. |
XMPD | known | A 32-bit length and XMP metadata as XML. |
Post | known | A 32-bit length and a PostScript font name. |
Famy | known | A 32-bit length and a font family name. |
Crvs, Stri | partly known | Curves and strings; contents not described. |
Shap, Symb, NgoL, UOrg | unknown | Seen in files; meaning not established. |
Unknowns
- The meaning of the version field and how it changed across Affinity 1, 2 and the 2025 Affinity app.
- The pixel storage of raster layers, adjustment and live filter layers, masks and the blend mode values.
- Whether a flattened preview is stored and where.
- Whether later versions use compression other than zlib.