The codestream (ISO/IEC 18181-1) is a bit stream, not a byte layout: its headers
are packed fields of varying width. It runs: the signature FF 0A, the
size header, the image metadata, the custom transform data, an ICC profile if the
metadata asks for one, zero bits to the next byte, a preview frame if there is one,
then the frames. The ISO text is not freely
available; the field lists here follow libjxl’s header code.
How fields are coded
Bits are read least significant first: the first field starts at bit 0 of the first byte, and a field of n bits takes its lowest bit first.
| Coding | How it is read |
|---|---|
| Bool | 1 bit. |
| Bits(n) | n bits as an unsigned number. |
| U32(d0, d1, d2, d3) | A 2-bit selector picks one of four distributions. Val(v) is the constant v with no more bits; BitsOffset(n, o) reads n bits and adds o; Bits(n) is BitsOffset(n, 0). |
| U64 | 2-bit selector: 0 is 0; 1 is 1 + 4 bits; 2 is 17 + 8 bits; 3 is 12 bits, then while a 1 bit follows, 8 more bits above the previous ones (4 bits for the last group at shift 60). |
| F16 | 16 bits, IEEE half precision: sign bit 15, exponent bits 10 to 14 (bias 15), mantissa bits 0 to 9. Infinity and NaN are invalid. |
| Enum | U32(Val(0), Val(1), BitsOffset(4, 2), BitsOffset(6, 18)), so 0 to 81; values not defined for that enum are invalid. |
| all_default | Most header bundles start with a Bool: 1 means every field takes its default and nothing else of the bundle is coded. |
| extensions | A U64 bit mask; for each set bit a U64 count of bits follows, and those bits are skipped by readers that do not know the extension. |
| name | A length, U32(Val(0), Bits(4), BitsOffset(5, 16), BitsOffset(10, 48)), then that many bytes of UTF-8. |
| signed values | Coded unsigned: even u means u ÷ 2, odd u means −(u + 1) ÷ 2. |
Unconfirmed: the name length distribution, and the exact position of the custom transform data in the header sequence, are given from memory of libjxl and have not been checked against the standard.
SizeHeader
| Field | Coding | Condition | Meaning |
|---|---|---|---|
| small | Bool | 1 when both sizes are multiples of 8 up to 256. | |
| ysize_div8_minus_1 | Bits(5) | small | Height = (value + 1) × 8. |
| ysize | U32(BitsOffset(9, 1), BitsOffset(13, 1), BitsOffset(18, 1), BitsOffset(30, 1)) | not small | Height in pixels. |
| ratio | Bits(3) | 0: the width is coded; 1 to 7: width = floor(height × ratio). | |
| xsize_div8_minus_1 | Bits(5) | ratio 0 and small | Width = (value + 1) × 8. |
| xsize | as ysize | ratio 0, not small | Width in pixels. |
| ratio | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|
| width : height | 1 : 1 | 12 : 10 | 4 : 3 | 3 : 2 | 16 : 9 | 5 : 4 | 2 : 1 |
A 256 × 256 image codes small 1, ysize_div8_minus_1 31 and ratio 1, so the byte
after FF 0A is 7F (bits 1, 11111, then the low two bits of
ratio 001).
ImageMetadata
| Field | Coding | Default | Meaning |
|---|---|---|---|
| all_default | Bool | 1: 8-bit, no extra channels, XYB, sRGB, orientation 1. | |
| extra_fields | Bool | 0 | 1 when the next five fields and tone mapping are present. |
| orientation | Bits(3) + 1 | 1 | Only with extra_fields; table below. |
| have_intrinsic_size, intrinsic_size | Bool, SizeHeader | 0 | Only with extra_fields: the size to display the image at. |
| have_preview, preview | Bool, PreviewHeader | 0 | Only with extra_fields: a preview frame follows the headers. |
| have_animation, animation | Bool, AnimationHeader | 0 | Only with extra_fields. |
| bit_depth | BitDepth | 8-bit integer | Of the colour channels. |
| modular_16_bit_buffer_sufficient | Bool | 1 | 1 when 16-bit integers suffice for modular decoding. |
| num_extra_channels | U32(Val(0), Val(1), BitsOffset(4, 2), BitsOffset(12, 1)) | 0 | Then one ExtraChannelInfo each. |
| xyb_encoded | Bool | 1 | 1 when the image is stored in the XYB colour space (lossy); 0 when stored in the declared colour space (needed for lossless). |
| colour_encoding | ColourEncoding | sRGB | With XYB, the space to convert to; otherwise the space of the samples. |
| tone_mapping | ToneMapping | Only with extra_fields. | |
| extensions | extensions | 0 |
BitDepth
| Field | Coding | Condition | Meaning |
|---|---|---|---|
| floating_point_sample | Bool | 1 for floating-point samples. | |
| bits_per_sample | U32(Val(8), Val(10), Val(12), BitsOffset(6, 1)) | integer | 1 to 31 bits (level 5 allows up to 16). |
| bits_per_sample | U32(Val(32), Val(16), Val(24), BitsOffset(6, 1)) | float | Total bits of the float. |
| exponent_bits_per_sample | Bits(4) + 1 | float | 2 to 8; the mantissa (bits − exponent − 1) must be 2 to 23. |
ExtraChannelInfo
| Field | Coding | Condition | Meaning |
|---|---|---|---|
| all_default | Bool | 1: an 8-bit alpha channel, not premultiplied. | |
| type | Enum | Table below. | |
| bit_depth | BitDepth | ||
| dim_shift | U32(Val(0), Val(3), Val(4), BitsOffset(3, 1)) | The channel is 2dim_shift times smaller in each direction (at most 8 times). | |
| name | name | ||
| alpha_associated | Bool | alpha | 1 when colour is premultiplied by this alpha. |
| spot_color | 4 × F16 | spot colour | Red, green, blue and solidity of the ink. |
| cfa_channel | U32(Val(1), Bits(2), BitsOffset(4, 3), BitsOffset(8, 19)) | CFA | Which colour filter array channel this is. |
| type | Meaning |
|---|---|
| 0 | Alpha |
| 1 | Depth |
| 2 | Spot colour |
| 3 | Selection mask |
| 4 | Black, the K of CMYK (level 10 only) |
| 5 | Colour filter array (Bayer) channel |
| 6 | Thermal |
| 7 to 14 | Reserved; invalid |
| 15 | Unknown: identified by its name; decoders warn if they do not support it |
| 16 | Optional: like unknown, but may be ignored silently |
ColourEncoding
| Field | Coding | Condition | Meaning |
|---|---|---|---|
| all_default | Bool | 1: sRGB. | |
| want_icc | Bool | 1: an ICC profile follows the headers and describes the colour; the fields below are left out. | |
| colour_space | Enum | 0 RGB, 1 grey, 2 XYB, 3 unknown. | |
| white_point | Enum | no ICC, not XYB | 1 D65, 2 custom, 10 E (equal energy), 11 DCI. |
| white | Customxy | white_point 2 | |
| primaries | Enum | no ICC, RGB | 1 sRGB (BT.709), 2 custom, 9 BT.2100, 11 P3. |
| red, green, blue | 3 × Customxy | primaries 2 | |
| have_gamma | Bool | no ICC, not XYB | 1: a pure gamma curve. |
| gamma | Bits(24) | have_gamma | The gamma value × 107. |
| transfer_function | Enum | no gamma | 1 BT.709, 2 unknown, 8 linear, 13 sRGB, 16 PQ, 17 DCI (gamma 2.6), 18 HLG. |
| rendering_intent | Enum | no ICC | 0 perceptual, 1 relative colorimetric, 2 saturation, 3 absolute colorimetric. |
A Customxy is a CIE x then y, each coded signed with U32(Bits(19), BitsOffset(19, 524288), BitsOffset(20, 1048576), BitsOffset(21, 2097152)) and divided by 106. The numbers of the white point, primaries and transfer function enums are those of ITU-T H.273, as used in HEIF colr. The ICC profile, when wanted, is entropy coded; its coding is not described on this site.
ToneMapping
| Field | Coding | Default | Meaning |
|---|---|---|---|
| all_default | Bool | ||
| intensity_target | F16 | 255 | Peak brightness of the image, in nits. |
| min_nits | F16 | 0 | Darkest level, 0 to intensity_target. |
| relative_to_max_display | Bool | 0 | 1 when linear_below is a fraction of the display’s maximum rather than nits. |
| linear_below | F16 | 0 | Below this level tone mapping should be linear. |
PreviewHeader and AnimationHeader
| Field | Coding | Condition | Meaning |
|---|---|---|---|
| div8 | Bool | preview | 1 when the sizes are coded in units of 8. |
| ysize_div8 | U32(Val(16), Val(32), BitsOffset(5, 1), BitsOffset(9, 33)) | div8 | Height = value × 8. |
| ysize | U32(BitsOffset(6, 1), BitsOffset(8, 65), BitsOffset(10, 321), BitsOffset(12, 1345)) | not div8 | Height. |
| ratio | Bits(3) | preview | As in SizeHeader. |
| xsize_div8, xsize | as ysize | ratio 0 | Width. |
| tps_numerator | U32(Val(100), Val(1000), BitsOffset(10, 1), BitsOffset(30, 1)) | animation | Ticks per second = numerator ÷ denominator. |
| tps_denominator | U32(Val(1), Val(1001), BitsOffset(8, 1), BitsOffset(10, 1)) | animation | |
| num_loops | U32(Val(0), Bits(3), Bits(16), Bits(32)) | animation | 0 means loop forever. |
| have_timecodes | Bool | animation | 1 when each frame carries a 32-bit timecode. |
CustomTransformData
| Field | Coding | Condition | Meaning |
|---|---|---|---|
| all_default | Bool | ||
| opsin_inverse_matrix | all_default Bool, then 9 + 3 + 4 F16 | xyb_encoded | The 3 × 3 matrix from XYB to linear RGB, the three opsin biases and four quantisation biases; defaults are libjxl’s standard values. |
| custom_weights_mask | Bits(3) | Bit 0: 15 F16 weights for 2× upsampling follow; bit 1: 55 for 4×; bit 2: 210 for 8×. |
Orientation
| Value | Operation from stored to displayed image |
|---|---|
| 1 | None |
| 2 | Flip horizontally |
| 3 | Rotate 180° |
| 4 | Flip vertically |
| 5 | Transpose |
| 6 | Rotate 90° clockwise |
| 7 | Anti-transpose |
| 8 | Rotate 90° anticlockwise |
The values match Exif. The codestream orientation overrides any Exif orientation in the container.