Search code examples
pngzlib

Put png scanlines image data to zlib stream with no compressing?


I am making a simple png image from scratch. I have had the scanlines data for it. Now I want to make it into zlib stream without being compressed. How can I do that? I have read the "ZLIB Compressed Data Format Specification version 3.3" at "https://www.ietf.org/rfc/rfc1950.txt" but still not understanding. Could someone give me a hint about setting the bytes in zlib stream?

Thanks in advance!


Solution

  • As mentioned in RFC1950, the details of the compression algorithm are described in another castle RFC: DEFLATE Compressed Data Format Specification version 1.3 (RFC1951).

    There we find

      3.2.3. Details of block format
    
         Each block of compressed data begins with 3 header bits
         containing the following data:
    
            first bit       BFINAL
            next 2 bits     BTYPE
    
         Note that the header bits do not necessarily begin on a byte
         boundary, since a block does not necessarily occupy an integral
         number of bytes.
    
         BFINAL is set if and only if this is the last block of the data
         set.
    
         BTYPE specifies how the data are compressed, as follows:
    
            00 - no compression
            [... a few other types]
    

    which is the one you wanted. These 2 bits BTYPE, in combination with the last-block marker BFINAL, is all you need to write "uncompressed" zlib-compatible data:

      3.2.4. Non-compressed blocks (BTYPE=00)
    
         Any bits of input up to the next byte boundary are ignored.
         The rest of the block consists of the following information:
    
              0   1   2   3   4...
            +---+---+---+---+================================+
            |  LEN  | NLEN  |... LEN bytes of literal data...|
            +---+---+---+---+================================+
    
         LEN is the number of data bytes in the block.  NLEN is the
         one's complement of LEN.
    

    So, the pseudo-algorithm is:

    1. set the initial 2 bytes to 78 9c ("default compression").
    2. for every block of 32768 or less bytesᵃ
      1. if it's the last block, write 01, else write 00
      2. ... write [block length] [COMP(block length)]
      3. ... write the immediate data
    3. repeat until all data is written.

    Don't forget to add the Adler-32 checksum at the end of the compressed data, in big-endian order, after 'compressing' it this way. The Adler-32 checksum is to verify the uncompressed, original data. In the case of PNG images, that data has already been processed by its PNG filters and has row filter bytes appended – and that is "the" data that gets compressed by this FLATE-compatible algorithm.


    ᵃ This is a value that happened to be convenient for me at the time; it ought to be safe to write blocks as large as 65535 bytes (just don't try to cross that line).

    ᵇ Both as words with the low byte first, then high byte. It is briefly mentioned in the introduction.