After the headers, an OpenEXR file holds one offset table per part and then the chunks of pixels. All numbers are little-endian; the sizes of the basic types are on the attribute types page.
Offset tables
Each entry is an unsigned long: the offset of a chunk from the start of
the file.
- In a single-part file with no
chunkCount, the number of entries comes fromdataWindow,tilesand the compression. - In a multi-part file, the number of entries is
chunkCount. - Scan line chunks are listed by increasing y, tiles by increasing y order.
Part number
In a multi-part file (version bit 12 set), every chunk starts with an
unsigned long part number. Part 0 is the first header’s part. Other files
have no part number.
Scan line chunk
| Field | Type | Description |
|---|---|---|
| y | int | The top scan line of the block. The first block matches the data window’s minimum y. |
| Pixel data size | int | Bytes of pixel data. |
| Pixel data | bytes | The pixels, compressed if that made them smaller. |
Uncompressed pixels are stored top to bottom. Within each scan line the channels are in alphabetical order, each channel’s values together, left to right. The last block can hold fewer lines if the data window height is not a whole number of blocks.
| Compression | Scan lines per block |
|---|---|
NO_COMPRESSION | 1 |
RLE_COMPRESSION | 1 |
ZIPS_COMPRESSION | 1 |
ZIP_COMPRESSION | 16 |
PIZ_COMPRESSION | 32 |
PXR24_COMPRESSION | 16 |
B44_COMPRESSION | 32 |
B44A_COMPRESSION | 32 |
DWAA_COMPRESSION | 32 |
DWAB_COMPRESSION | 256 |
HTJ2K256_COMPRESSION | 256 |
HTJ2K32_COMPRESSION | 32 |
Tile chunk
| Field | Type | Description |
|---|---|---|
| Tile coordinates | 4 × int | tileX, tileY, levelX, levelY. |
| Pixel data size | int | Bytes of pixel data. |
| Pixel data | bytes | As for a scan line, using the tile’s width and height. |
Tiles at the right or bottom edge of a level can be narrower or shorter than the others.
Deep scan line chunk
Deep images store a variable number of samples per pixel. A deep scan line chunk is:
| Field | Type | Description |
|---|---|---|
| Part number | unsigned long | Only in multi-part files. |
| y | int | The scan line. |
| Packed size of the pixel offset table | not stated in the layout document | Bytes of compressed offset table. |
| Packed size of the sample data | not stated in the layout document | Bytes of compressed sample data. |
| Unpacked size of the sample data | unsigned long | Bytes once expanded. |
| Pixel offset table | compressed | The sample counts. |
| Sample data | compressed | The samples. |
A deep tile chunk has the same fields, with tile coordinates in place of y. The pixel
offset table has one int per column in the data window: entry n is the
total sample count of column n and all columns to its left.
Unpacked sample data stores all samples of the first channel, then all of the second,
and so on. With ZIP_COMPRESSION, up to 16 scan lines are stored together,
with the channels grouped within each scan line.
Deep parts may use only NO_COMPRESSION, RLE_COMPRESSION,
ZIPS_COMPRESSION or ZIP_COMPRESSION.
A complete file
The OpenEXR project’s sample is a 415-byte, uncompressed, single-part scan line file,
4 by 3 pixels, with channels G (half) and Z (float). Its
offset table holds 319, 351 and 383, one per scan line, and each block has 24 bytes of
pixel data: 4 × 2 bytes of G and 4 × 4 bytes of Z.