-1

I'm having trouble inflating the png IDAT chunk back to RGB data.

void PNG::IDAT()
{
    int index = 0;
    char CMF = m_data[index];
    index++;

    //big endian
    char CM = CMF & 0b00001111;
    char CINFO = CMF & 0b11110000; 
    //For CM = 8, CINFO is the base-2 logarithm of the LZ77 window  size, minus eight(CINFO = 7 indicates a 32K window size).

    char FLG = m_data[index];
    index++;

    char FCHECK = FLG & 0b00011111; 
    //The FCHECK value must be such that CMF and FLG, when viewed as a 16 - bit unsigned integer stored in MSB order(CMF * 256 + FLG),  is a multiple of 31. //effort
    char FDICT =  FLG & 0b00100000;
    char FLEVEl = FLG & 0b11000000;

    char DICTID[4];
    if (FDICT > 0)
    {
        memcpy(DICTID, &m_data[index], 4);
        index += 4;
    }

    uLong outputLength = compressBound(m_length); 
    char* output = new char[outputLength];


    z_stream infstream;
    infstream.zalloc = Z_NULL;
    infstream.zfree = Z_NULL;
    infstream.opaque = Z_NULL;
    infstream.avail_in = m_length; // size of input
    infstream.next_in = (Bytef *)m_data; // input char array
    infstream.avail_out = outputLength; // size of output
    infstream.next_out = (Bytef *)output; // output char array

    inflateInit2(&infstream, 16 + MAX_WBITS);
    inflate(&infstream, Z_NO_FLUSH);
    inflateEnd(&infstream);


    for (size_t i = 0; i < outputLength; i+= 3)
    {
        pixel temp;
        temp.r = output[i + 0];
        temp.g = output[i + 1];
        temp.b = output[i + 2];
        m_pixels.push_back(temp);
    }
}

Inflate returns error code -3, which means "Z_DATA_ERROR". I've followed the RFC-1950 and RFC-1951 standards but I'm confused as to which bytes actually need to be streamed into the inflate function and which need to be stripped. m_data is literally just the data from the chunk without the length, type and CRC. m_length in turn is only the length given by said chunk.

Input is also just plain RGB, with compression mode 0, filter mode 0 and interlace mode 0.

CM is 8.

CMINFO is 112.

FCHECK is 30.

FDICT is 0.

FLEVEL is 64.

TL;DR: what exactly does the inflate function from zlib want/need?

Here's also a picture of the hex values of the image I'm trying to read. picture link because stackoverflow doesn't allow new users to post pics

Sam iets
  • 1
  • 1
  • Does that picture-of-text show the exact start where you are trying to decompress? It starts with a few other data blocks that are not compressed. – Jongware Nov 26 '18 at 10:29
  • @usr2564301 ah my bad, here's a full picture [link](https://imgur.com/a/ZX0s4Cf) – Sam iets Nov 27 '18 at 00:44

1 Answers1

1

The 78 5e ed d1 ... right after the IDAT is the start of the zlib stream. It is 288 bytes long, and is a valid zlib stream, as is all of the PNG data. If you have read the data correctly, fed the correct portion to inflate, and provided enough output space (see #2 below), then it will work.

Some comments on your code:

  1. You do not need to try to decode the zlib header. Just feed the whole thing to inflate.
  2. compressBound() is of no use here. That is only for compression, not decompression. That 228 bytes of compressed data decompresses to 47,234 bytes. Far more than you have allocated space for.
  3. The resulting decompressed data is not the raw RGB pixels. Each line of the image starts with a filter byte, and the remaining bytes in the line need to be interpreted accordingly.
  4. You need to check for return code and errors from the zlib functions. Always check return codes. Always.
Mark Adler
  • 79,438
  • 12
  • 96
  • 137
  • but then what should you use to find the size of the output buffer? I guess you could kinda figure it out with PNG based on all the info from the header file, but otherwise it's just a wild guess, right? Are you just supposed to make big margins so you don't hit a limit or is there some kind of best-case-scenario compression rate on which you can base the size of? – Sam iets Nov 28 '18 at 05:26
  • 1
    You can calculate it exactly from the header information. – Mark Adler Nov 28 '18 at 06:02
  • 47234 == 113 * (1 + 139 * 3). The 1 is the filter byte on each line. – Mark Adler Nov 28 '18 at 15:45