HALICERY

free-time coding, hardware dev, articles

Top
Home 8042 Blogs About
Home Image Decoders PNG PNGFile

Last modified: Thu Jul 23 14:48:27 UTC+0200 2026 © A. Tarpai


PNG file structure

      8-byte
    SIGNATURE

| % P N G . . . . | .. CHUNK .. .. | .. CHUNK .. .. .. .. .. .. | .. CHUNK .. .. .. .. .. .. .. | .. CHUNK .. |

The chunks

Each CHUNK consists of four parts (the boxes are bytes):

     +---+---+---+---+   +---+---+---+---+   +---+--- - - --+---+---+---+---+   +---+---+---+---+
     |   |   |   |   |   |   |   |   |   |   |                              |   |   |   |   |   |
     +---+---+---+---+   +---+---+---+---+   +---+--- - - --+---+---+---+---+   +---+---+---+---+
          Length            Chunk Type          Chunk Data (Length bytes)             CRC


 "Critical chunks (must appear in this order, except PLTE is optional):

        Name   Multiple  Ordering constraints

        IHDR    No       Must be first
        PLTE    No       Before IDAT (optional)
        IDAT    Yes      Multiple IDATs must be consecutive
        IEND    No       Must be last"

This decoder supports only critical chunks (the others are quite client-dependent) with multiple IDAT:

   SIG..IHDR...PLTE........IDAT..................IDAT...........................IDAT..........IEND

Traversing the chunk structure

Read SIG
{
  Length <- GetDWord
  Type <- GetDWord
  seek(Length)
  CRC <- GetDWord
}
until (Type == IEND)

The IDAT chunk(s)

Concatenation of all IDAT contains a zlib-compressed bit-stream using the Deflate algorithm. The first

"There can be multiple IDAT chunks; if so, they must appear consecutively with no other intervening chunks." (http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html)

IDAT .. .. .. .. .. .. .. .. .. .. ..  IDAT .. .. .. .. .. .. ..  IDAT .. .. .. .. ..
               |
               |
               | NextByte
               |
          +-------- inflate --------+
          |                         |
          |                         |  ------> uncompressed data bytes
          |                         |
          |                         |
          +-------------------------+

Notes.

I wanted to implement 'transparently' for inflate() to get the next byte from the compressed datastream. It simply calls back a function (NextByte) set by the client (run-time binding, OS dev habits..). Again, allocated buffers vs. speed to 'concatenate' or not the IDAT chunks.

Concatenation of all IDAT contains a zlib-compressed bit-stream (lsb-first)

zlib-block......zlib-block......zlib-block......zlib-block* (*final zlib-block has first bit set, bfinal)

zlib-block:

     HEAD   HT DEFINITIONS           COMPRESSED DATA               EOD
    \____/\_______________/\_____________________________________/\___/


    [0][10][10010][10010][1110][010][110][000]...[001][01][01001][1110][010]...........[0001][010][1110][10010]....[10][......COMPRESSED DATA......][EOD]
    \_/\__/\_____/\_____/\____/\_____________________/\________________________________/\______________________________/\__________________________/\___/
bfinal btype hlit  hdist  hclen     len-of-len           len-of-literals/ptr-lenghts           len-of-distance
                                                                                                                             |
                                       / \                       / \                              / \                        |
                                      2   x                     x   x                            x   x                       |
                                         / \                   / \ / \                          / \ / \                       ----- literal
                                                              4  x x  x                        4  7 x  x                      ----- length/dist
                                                                /\ /\ /\                            /\ /\                     ----- EOD

                                                  ..we build 3 Huffman trees..