Search code examples
pngzlib

How does zlib decompression work on a PNG IDAT chunk?


I am trying to understand how PNG files work. I am stuck on how you decompress the IDAT data. I have searched the whole Internet, but I haven't found anything that I understand.

I have this HEX Code of an example PNG.

I have extracted the data of the IDAT chunk, here in hexadecimal: 08 1D 63 60 60 60 F8 0F 00 01 04 01 00 1E 73 9C 40.

I don't understand how to decompress this. I got as far as the first byte, which is the compression mode/flag code, and the second byte, which is additonal flags, and the last four bytes is the check value. What do they mean and how you decompress now the data?

I think I will understand it with one or more examples. Here is an IDAT chunk from a different PNG file: 18 19 62 64 60 f8 fa 9f 01 08 00 00 00 00 ff ff 63 64 60 f8 fa 9f 81 e1 3f 03 00 29 31 04 ea.

I would really appreciate it if someone could explain to me for those two examples how zlib decoding works.


Solution

  • Your first example was not correctly extracted, as it has four extraneous bytes on the end. If you remove the last four bytes, then you have a complete and valid zlib stream.

    The second example is a complete and valid zlib stream as presented.

    You need to read RFC 1950 for the zlib wrapper format, which describes the first two and last four bytes of each zlib stream. What remains in between is deflate compressed data, for which you will need to read RFC 1951.

    Both example streams used fixed blocks, so even once you understand how to decompress those, you will still have more to learn about decompressing dynamic blocks. You should find larger .PNG files for examples of those.

    To give you a clue, here are disassemblies of those two streams using infgen:

    ! infgen 3.0 output
    !
    zlib
    !
    last
    fixed
    literal 0 0 0 0 255
    end
    !
    adler
    

    and:

    ! infgen 3.0 output
    !
    zlib
    !
    fixed
    literal 1 0 0 245 255 0
    match 3 1
    end
    !
    stored
    end
    !
    last
    fixed
    literal 1 0 0 245 255 0 0 255 0
    end
    !
    adler
    

    You don't really need to know any of this however to decode PNG files. You can just use the zlib library to decompress the data.