PNG decode data from IDAT chunk

70 Views Asked by At

I'm trying to make a png file reader in c++. I understood about the chunk structure but I'm struggling in understanding how to read the data in "IDAT" chunk to get each pixel color. This is my data

width: 16 height: 16 bit depth: 8 color type: 2 compression method: 0 filter method: 0 interlace method: 0

IDAT data: 38 4F 63 FC CF 40 1A 60 82 D2 44 83 51 0D C4 80 51 0D C4 00 5A 6B 60 60 00 00 40 2E 01 1F(hex)

I don't know what to do to decode the data, can anyone explain me, even with just an example of a single pixel, thanks

1

There are 1 best solutions below

2
Mark Adler On

Well, first off, if your PLTE chunk has only three bytes, i.e. one color, then your image can consist of only one color. Every pixel is red! Every decoded bit for each pixel must be a 0, since if there is even a single pixel with value 1, then the PNG decoder is obliged to report an error, due to an out-of-range palette index.

Second, the IDAT data shown must be after decompression, since there is no zlib header. A 16x16 depth 1 image is stored in 48 bytes (One filter byte plus two pixel bytes per 16-pixel row, times 16 rows). The 11 bytes shown is far from sufficient. Furthermore, the first byte of uncompressed IDAT data is the filter type for that scan line, which must be in 0..4. It cannot be 8.

Bottom line: the data in your question cannot be decoded because it is not valid PNG data.

If your image had those attributes, that PLTE, but correct IDAT data, it would look like this:

red

Updated question with entirely different attributes and IDAT data:

Now what you have for the IDAT chunk is a zlib stream, which is what it must be. The first thing to do is to decompress it. You would use, for example, zlib's inflate to do that. Then you get 784 bytes, which is exactly what would be required for 16 rows * (1 filter byte + 16 columns * 3 bytes/pixel). Showing one row per line, ... representing repeated bytes in a row, and ... on a line by itself representing repeated lines, the 784 bytes are:

01 ff 00 00 ... 00
02 00 00 00 ... 00
02 00 00 00 ... 00
...
02 00 00 00 ... 00

The 01 on the first line means the "sub" filter, and 02's on the remaining lines mean the "up" filter. The ff 00 00 after the 01 is the first pixel, which is red. All of the remaining pixels then have zero difference from that first pixel, so, again, you end up with a 16x16 set of red pixels, the tiny image shown above.