Advertisement

Reading PNG format (deflate compression)

Started by October 21, 2014 12:55 AM
14 comments, last by Lehm2000 10 years, 3 months ago

Yes, like others say, "inside" the ZLIB stream is a PNG-filtered representation. The PNG filtered representation is an optimization step that PNG performs on the color data in order for DEFLATE to compress better than it would on the raw color data.


IDAT chunk { ZLIB { PNG Filters (each scanline starts with the filter ID that the scanline is using) { Color data } } }

2. Filter the image data according to the filtering method specified by the IHDR chunk. (Note that with filter method 0, the only one currently defined, this implies prepending a filter-type byte to each scanline.)


And the logic for encoding/decoding with the filters is here:

http://www.libpng.org/pub/png/spec/1.2/PNG-Filters.html

Filtering algorithms are applied to bytes, not to pixels, regardless of the bit depth or color type of the image. The filtering algorithms work on the byte sequence formed by a scanline that has been represented as described in Image layout. If the image includes an alpha channel, the alpha data is filtered in the same way as the image data."

For all filters, the bytes 'to the left of' the first pixel in a scanline must be treated as being zero. For filters that refer to the prior scanline, the entire prior scanline must be treated as being zeroes for the first scanline of an image (or of a pass of an interlaced image).


Unsigned arithmetic modulo 256 is used, so that both the inputs and outputs fit into bytes.


In other words, if you expect your final image data to start with the byte '255', and you have a scanline filter of 1 (sub), then your next byte should be a 1. (0 minus 1 -> modulo 256 -> 255) // NOTE: this is wrong and has been corrected (below)

[deleted]

Sorry - hold on. I made the wrong conclusion from some old code that didn't match with the spec (the result was correct but my explanation in this post was not). Fixed it in the below post (it was supposed to be another edit but I messed that up too).

Advertisement

In other words, if you expect your final image data to start with the byte '255', and you have a scanline filter of 1 (sub), then your next byte should be a 1. (0 minus 1 -> modulo 256 -> 255)

Not quite.

For the first byte, you can just write the raw value. The equation is (curr - prev), and x < 0 is defined as 0. So filtering with the PNG subtraction filter would give 255 - 0, mod 256, which is still 255. So byte 1 would be "1" for sub filter, and byte 2 would be "255".

In other words, if you expect your final image data to start with the byte '255', and you have a scanline filter of 1 (sub), then your next byte should be a 1. (0 minus 1 -> modulo 256 -> 255)


Not quite.

For the first byte, you can just write the raw value. The equation is (curr - prev), and x < 0 is defined as 0. So filtering with the PNG subtraction filter would give 255 - 0, mod 256, which is still 255. So byte 1 would be "1" for sub filter, and byte 2 would be "255".


Oops, you're right. I read the encoding and decoding parts backwards. Decoding *adds* the previously decoded byte (zero if there is no previous value) with the current byte, so the first filtered byte using the Sub filter is effectively the same before/after encoding/decoding.

So I assume you are not wanting to use zlib?

Id suggest you tackle this the same way I believe libpng does. Get a working DEFLATE first (i.e. implement your own version of the zlib decompression stuff, which you can also test easily against zlib on simple binary strings for correctness), then use that to implement the PNG decoding stuff.


In other words, if you expect your final image data to start with the byte '255', and you have a scanline filter of 1 (sub), then your next byte should be a 1. (0 minus 1 -> modulo 256 -> 255)

Not quite.

For the first byte, you can just write the raw value. The equation is (curr - prev), and x < 0 is defined as 0. So filtering with the PNG subtraction filter would give 255 - 0, mod 256, which is still 255. So byte 1 would be "1" for sub filter, and byte 2 would be "255".

Spot on. Thanks for the help. I totally looked over the filter info. There was also an error in the code that returned 79 for the second byte. Once I fixed that I got 255 for the second byte.

This topic is closed to new replies.

Advertisement