BNG IMAGE FORMAT SPECIFICATION
Container identifier BTPNGF, version 1.  File extension .bng.
Revision of 2026-09-23.  This document describes the format only.


0. CONVENTIONS

All integers stored in a file are unsigned and little-endian.

"Byte" means eight bits.  Bit positions within a byte are numbered from
0 for the least significant bit to 7 for the most significant bit.

x & y, x | y are bitwise operations.  x >> n and x << n are shifts.  A
shift written as "arithmetic" propagates the sign bit.

"s as int8" means the byte s reinterpreted as a two's complement signed
8-bit value: s if s < 128, otherwise s - 256.

Arithmetic on samples, predictions and residual reconstruction is
performed modulo 256 unless stated otherwise.

The format defines no checksum.  A decoder can detect a truncated or
structurally invalid file, but cannot in general detect a corrupted one.


1. PIXELS

An image is a rectangular array of width x height pixels, width >= 1 and
height >= 1.

A pixel has four 8-bit channels, named B, G, R and A.  On the pixel side
of an encoder or decoder one pixel occupies four consecutive bytes in
this order:

    +0  B   blue
    +1  G   green
    +2  R   red
    +3  A   alpha

R, G and B are sRGB premultiplied by A:

    stored = (component x A + 127) / 255

A is linear coverage.  A stored component may exceed A, and A = 0 does
not imply that R, G and B are 0.

All four channels are coded losslessly and none of them is interpreted
by the format, so a fourth byte that carries padding rather than
coverage round-trips unchanged.  No gamma or ICC information is carried
by the format.

Rows on the pixel side are addressed by a pitch, the distance in bytes
between the first byte of one row and the first byte of the next, which
must be at least 4 x width.  The pitch is a property of the caller's
memory, not of the file, and is never stored.


2. FILE STRUCTURE

A file is a 20-byte header followed by a body.

    offset  size  field
    0       1     0xFF
    1       6     signature, the six bytes 0E 38 30 2A 1A 18
    7       1     version, the byte 0x01
    8       4     width in pixels, u32
    12      4     height in pixels, u32
    16      4     stream_byte_count, u32
    20      ...   body

Bytes 0..7 are constant for every version-1 file and may be compared
directly as the eight-byte sequence

    FF 0E 38 30 2A 1A 18 01

Bytes 1..6 spell "BTPNGF" in the Serenum CLEAR character encoding, which
is not ASCII, and byte 7 is "1" in that same encoding.  A decoder does
not need to know that encoding; the bytes are fixed.

stream_byte_count is interpreted as

    bit 31       RAW flag
    bits 0..30   body_length, the length of the body in bytes

The header is not included in body_length.  The total file length is
exactly

    20 + body_length

so a reader can find the end of an image without decoding it, and images
can be stored back to back in one stream.

If the RAW flag is set the body is stored as described in section 3.  If
it is clear the body is a coded bitstream, sections 4 to 11.


3. RAW BODY

With the RAW flag set the body is the pixel data itself: height rows of
width pixels, each pixel four bytes in the order B, G, R, A, rows packed
one after another with no padding between them.  body_length is then
exactly 4 x width x height; any other value makes the file invalid.

A raw body carries the same image a coded body would.  An encoder may
choose either; a decoder must accept both.  Because a raw body is never
longer than the pixels it stores, no file of a width w, height h image
exceeds

    20 + 4 x w x h

bytes.


4. CODED BODY: OVERVIEW

The coded body is produced by, in order:

    (1) the colour transform of section 5, applied per pixel, giving
        four planes of 8-bit samples;
    (2) the prediction of section 6, applied per plane, giving one
        residual per sample;
    (3) the tokenisation of sections 7 to 9;
    (4) the Huffman code of section 10, packed as in section 11.

A decoder reverses these steps.  Nothing about the code or the model is
stored in the file: sections 9 and 10 are fixed for all images.


5. COLOUR TRANSFORM

The transform is YCoCg-R, which is reversible on 8-bit channels.  It
produces three samples Y, Co, Cg from R, G, B.  The fourth plane carries
A unchanged.

Forward, from R, G, B to Y, Co, Cg:

    Co = (R - B) & 255
    t  = (B + ((Co as int8) >> 1)) & 255      arithmetic shift
    Cg = (G - t) & 255
    Y  = (t + ((Cg as int8) >> 1)) & 255      arithmetic shift

Inverse, from Y, Co, Cg to R, G, B:

    t = (Y - ((Cg as int8) >> 1)) & 255       arithmetic shift
    G = (Cg + t) & 255
    B = (t - ((Co as int8) >> 1)) & 255       arithmetic shift
    R = (B + Co) & 255

The four planes are numbered

    plane 0   Y
    plane 1   Co
    plane 2   Cg
    plane 3   A


6. PREDICTION

Each plane is predicted independently.  Within a plane, the sample at
column x of row y is predicted from three causal neighbours of the same
plane:

    L   the sample at (x - 1, y)
    T   the sample at (x, y - 1)
    TL  the sample at (x - 1, y - 1)

The predictor is MED, the median edge detector:

    mn   = min(L, T)
    mx   = max(L, T)
    g    = L + T - TL              computed as integers, not modulo 256
    pred = g < mn ? mn : (g > mx ? mx : g)

A neighbour that lies outside the image reads as 0, which needs no
special case: the prediction is 0 for the first sample of a plane, the
left neighbour throughout row 0, and the upper neighbour in column 0.

The residual of a sample s is

    e = (s - pred) & 255

interpreted as a signed value, e as int8, in the range -128..127.  The
reconstruction is

    s = (pred + e) & 255

Predictions use reconstructed samples, which in a lossless format are
the original samples.


7. RESIDUAL CODING

Each residual is coded as a token, optionally followed by a mantissa of
a width the token fixes.  A run of consecutive zero residuals within one
row of one plane may be coded as a single token.  The alphabet is
section 9.


8. SYMBOL ORDER

The body codes rows in increasing y, and within a row the four planes in
the order 0, 1, 2, 3:

    row 0 plane 0, row 0 plane 1, row 0 plane 2, row 0 plane 3,
    row 1 plane 0, ...

Each (row, plane) pair is a self-contained sequence of tokens covering
exactly width residuals, in increasing x.  A run token never crosses a
row or a plane boundary.  A decoder therefore holds rows, not planes,
and can emit an output row as soon as its four planes are decoded.


9. TOKEN ALPHABET

There are 144 tokens, numbered 0..143.  Each carries a base value, a
mantissa width in bits, and a kind.  The mantissa, when present, is
written immediately after the token, most significant bit first, and its
value is added to the base.

    token     kind          value                        mantissa bits
    0         residual      0                            0
    1..126    residual      +/- (tk + 1) / 2             0
                            positive if tk is odd,
                            negative if tk is even
    127..130  residual      +/- (2^ex + mantissa),       ex
                            ex = 6 + (tk - 127) / 2,
                            positive if tk is even,
                            negative if tk is odd
    131       end of row    the rest of the row is zero  0
    132..143  zero run      2^j + mantissa zeros,        j
                            j = tk - 131

Consequences of that table, stated explicitly:

  - Tokens 1..126 cover residual magnitudes 1..63 directly.  Token 1 is
    +1, token 2 is -1, token 3 is +2, token 4 is -2, and so on, to token
    125 = +63 and token 126 = -63.

  - Tokens 127..130 cover residual magnitudes 64..128 by exponent:
    token 127 is +(64 + m) with a 6-bit mantissa m, token 128 is
    -(64 + m) with a 6-bit mantissa, token 129 is +(128 + m) with a
    7-bit mantissa, token 130 is -(128 + m) with a 7-bit mantissa.
    Residuals lie in -128..127, so of the values above magnitude 127
    only -128 can occur, as token 130 with a zero mantissa.

  - Tokens 132..143 cover zero runs of length 2 to 8191: token 132 is
    2 + m with a 1-bit mantissa, covering runs of 2..3; token 133 is
    4 + m with a 2-bit mantissa, covering 4..7; and so on to token 143,
    4096 + m with a 12-bit mantissa, covering 4096..8191.

  - A single zero residual is token 0, not a run.

  - Token 131 ends the row: every remaining residual of the current row
    of the current plane is zero, however many there are.

No token in 0..143 is unused.


10. THE HUFFMAN CODE

One canonical Huffman code is used for every token, every plane and
every image.  It is part of the format; an encoder does not choose it.
The maximum codeword length is 12 bits.  The Kraft sum of the lengths is
exactly 1, so no codeword space is wasted and every 12-bit pattern
completes a codeword.

The code length in bits of each of the 144 tokens, in token order:

    tk 0..15      3  3  3  4  4  4  4  5  5  6  6  6  6  7  7  7
    tk 16..31     7  7  7  8  8  8  8  8  8  8  8  9  9  9  9  9
    tk 32..47     9  9  9  9  9 10 10 10 10 10 10 10 10 10 10 10
    tk 48..63    10 10 10 10 10 11 11 11 11 11 11 11 11 11 11 11
    tk 64..79    11 11 11 11 11 11 11 11 11 12 12 12 12 12 12 12
    tk 80..95    12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12
    tk 96..111   12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12
    tk 112..127  12 12 12 12 12 12 12 12 12 12 12 12 12 11 12  7
    tk 128..143   7 12 11  9  4  6  7  8  9 10 10 11 12 12 12 12

Codewords are assigned canonically: shorter lengths first, and within
one length in increasing token order.

    code = 0
    for L = 1 to 12:
        for tk = 0 to 143 in increasing order:
            if length[tk] == L:
                assign codeword code, of length L, to token tk
                code = code + 1
        code = code << 1

For decoding, let first[L] be the value of code at the start of length L
and count[L] the number of tokens of that length.  A decoder shifts bits
into an accumulator v one at a time, starting at L = 1 and increasing L
by one per bit.  When

    v - first[L] < count[L]

the codeword is complete, and the token is the (v - first[L])-th token,
counting from zero, among those of length L in increasing token order.


11. BIT PACKING

The body is a sequence of bits packed into bytes most significant bit
first: the first bit of the body is bit 7 of the body's first byte, the
second is bit 6, and so on.

A codeword is written most significant bit first, and its mantissa, if
it has one, follows immediately, also most significant bit first.

After the last token of the last row the body is padded with zero bits
to a byte boundary.  body_length counts that final byte.

Because the final byte is zero-padded, a decoder reading the last
codeword of a file may consume bits that were never written.  A decoder
must therefore supply zero bits past the end of the body rather than
failing immediately.  The image ends when width x height pixels have
been decoded; truncation is detected by body_length, not by running out
of bits.


12. ENCODING PROCEDURE

For each pixel apply section 5 to obtain the four plane samples.  For
each plane of each row, in the order of section 8, compute residuals per
section 6 and emit tokens for that row of that plane as follows, with x
starting at 0 and the row ending at width:

    if the residual at x is not zero:
        let a be its magnitude
        if a <= 63:
            emit token 2a - 1 for a positive residual,
                      token 2a     for a negative residual
        otherwise:
            let ex = floor(log2(a))
            emit token 127 + 2 x (ex - 6) for a positive residual,
                      token 128 + 2 x (ex - 6) for a negative residual
            emit ex mantissa bits holding a - 2^ex
        advance x by 1

    otherwise let run be the number of consecutive zero residuals
    starting at x:
        if x + run == width:
            emit token 131, and the row is finished
        if run == 1:
            emit token 0 and advance x by 1
        otherwise:
            if run > 8191, set run = 8191
            let j = floor(log2(run))
            emit token 131 + j
            emit j mantissa bits holding run - 2^j
            advance x by run

A trailing run that reaches the end of a row is always token 131, even
when it is a single zero, so token 0 never appears as the last token of
a row.

After the last row, flush the bit writer with zero padding and write the
header, with body_length set to the number of body bytes produced and
the RAW flag clear.

An encoder whose coded body would reach 4 x width x height bytes should
write a raw body instead, per section 3.  Either choice is valid.


13. DECODING PROCEDURE

Validate the header as in section 14.  If the RAW flag is set, copy the
pixels out of the body as in section 3, and stop.

Otherwise decode row by row.  For each row, for each plane 0..3, fill
width residuals:

    read a token
    read its mantissa, if it has one, and add it to the token's base
    if the token is a residual token:
        store the signed value at x and advance x by 1
    if the token is a zero run or the end of row token:
        let n be its value; if n exceeds the number of residuals
        remaining in the row, reduce n to that number
        store n zeros and advance x by n
        if n is zero, the file is invalid

Reconstruct that plane's samples with section 6.  When all four planes
of the row are reconstructed, invert the colour transform with section 5
and write the row's pixels at the caller's pitch.

A decoder that meets a bit pattern completing no codeword within 12 bits
must reject the file.


14. CONFORMANCE

A decoder must reject a file if any of the following holds:

  - the file is shorter than 20 bytes;
  - bytes 0..6 are not FF 0E 38 30 2A 1A 18;
  - byte 7 is not 0x01;
  - width is 0, or height is 0;
  - width x height exceeds the decoder's own pixel budget, which it must
    apply before allocating anything;
  - body_length exceeds the number of bytes available after the header;
  - the RAW flag is set and body_length is not exactly
    4 x width x height;
  - a codeword is not completed within 12 bits;
  - a zero run token advances the position by zero.

A decoder must not read past 20 + body_length, and must accept a stream
that continues with further data after that point.

A file is valid if it decodes under these rules.  Because the format
carries no checksum, a file whose body bytes have been altered may still
decode, to different pixels.  Integrity protection, where it is needed,
belongs to the layer around the file.


15. LIMITS

    maximum width              2^32 - 1, subject to the pixel budget
    maximum height             2^32 - 1, subject to the pixel budget
    recommended pixel budget   2^28 pixels
    maximum body length        2^31 - 1 bytes
    maximum file length        20 + 4 x width x height bytes
    channels                   4, of 8 bits each
    codeword length            1..12 bits
    alphabet                   144 tokens
    maximum zero run           8191 samples, or to the end of a row
