Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ PNG header missread IHDR data chunk length, width and height

Tags:

c++

png

I am trying to create a method for a class that simply reads the PNG file up to the end of the IHDR Image header (without its CRC32 chunk. The trouble comes with every "more than one byte" integers (i.e IHDR data chunk length, width and height). Here is my code:

#include <iostream>
#include <fstream>
using namespace std;

typedef struct PNG_HEADER pngHeader;
struct PNG_HEADER{
    unsigned char PNGSignature[8];
    size_t nb;
    unsigned char ImageHeader[4];
    size_t width;
    size_t height;
    unsigned char bitDepth;
    unsigned char colorType;
    unsigned char compressionMethod;
    unsigned char filterMethod;
    unsigned char interlaceMethod;
};

class testPNG{

public:

    bool readPNGHeader(string filename){
        pngHeader PNGheader;

        ifstream file(filename.data(), std::ios_base::binary);

        if(!file.is_open())
            return false;

        if( !file.read((char *)&PNGheader, sizeof(PNGheader)))
            return false;


        for(int i = 0; i < 8; i++)
                printf("%d ", PNGheader.PNGSignature[i]);

        printf("\n");
        printf("%d\n", PNGheader.nb);

        for(int i = 0; i < 4; i++)
                printf("%d ", PNGheader.ImageHeader[i]);

        printf("\n");
        printf("%d\n", PNGheader.width );
        printf("%d\n", PNGheader.height );
        printf("%d\n", PNGheader.bitDepth );
        printf("%d\n", PNGheader.colorType );
        printf("%d\n", PNGheader.compressionMethod );
        printf("%d\n", PNGheader.filterMethod );
        printf("%d\n", PNGheader.interlaceMethod );

        return true;
    }
};


int main(void)
{
    testPNG test;
    test.readPNGHeader("test.png");

    return 0;
}

And the printed result is this (comments not shown on the console obviously):

137 80 78 71 13 10 26 10 //[PNG Signature OK!][1]
218103808                //this should read 13 as the length is the sum of the number of byte needed for each data field contained in the IHDR Data chunk that follows the IHDR Image Header chunk.
73 72 68 82              //[IHDR Image Header chunk OK!][2]
1879244800               //fail to give the correct width
973078528                //fail to give the correct height
8                        // OK!
6                        // OK!
0                        // OK!
0                        // OK!
0                        // OK!

As it is written on the w3c website; the length value (of data chunk) is stored in "A four-byte unsigned integer" . The same goes with the width and height of the image. And so I tried unsigned int and unsigned short too but nothing seems to work.

Even though I used printfs (I don't know how to format chars as ints with cout), I am looking for a C++ solution if possible.

Thank you

like image 956
Paiku Han Avatar asked Nov 19 '25 01:11

Paiku Han


1 Answers

Your machine, or your compiler, uses a reverse order to store multi-byte values in.

See "7.1 Integers and byte order" in that same reference:

All integers that require more than one byte shall be in network byte order ...

followed by a diagram that illustrates it.

To get the correct value for your number of bytes, reverse them using one of the predefined functions (of which I can never recall which one does what; please read How do you write (portably) reverse network byte order?) or write your own.

Your sample value 218103808 shows 0xD000000 when printed in hex; reversing the bytes produces the correct, expected result 0xD or 13.

like image 198
Jongware Avatar answered Nov 21 '25 16:11

Jongware



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!