C++ PNG头文件错误读取IHDR数据块长度、宽度和高度

3

我正在尝试为一个类创建一个方法,该方法简单地读取PNG文件直到IHDR图像头的结尾(不包括其CRC32块)。问题在于每个“多字节”整数(即IHDR数据块长度、宽度和高度)。以下是我的代码:

#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;
}

以下是输出结果(注释在控制台上不显示):
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!

如w3c网站所述,数据块的长度值存储在"四字节无符号整数"中。图像的宽度和高度也是如此。我尝试了无符号整数和无符号短整数,但似乎都不起作用。
即使我使用了printf(我不知道如何使用cout将字符格式化为整数),如果可能的话,我正在寻找一个C++解决方案。
谢谢
1个回答

4

你的机器,或者编译器,在存储多字节值时使用了反向顺序。

在同一参考文献中查看“7.1 整数和字节顺序”:

所有需要超过一个字节的整数都应该采用网络字节顺序...

随后是一张说明它的图表。

为了获得正确的字节数,可以使用预定义的函数之一来反转它们(我经常无法记住哪个函数做什么,请阅读如何编写(可移植的)反转网络字节顺序的代码?),或自己编写一个函数。

你的示例值218103808在十六进制打印时显示为0xD000000;反转字节后,就会产生正确的期望结果0xD13


我使用了gcc,因为你提供的链接中的代码(如果它确实交换了字节)给出的结果与未交换字节版本相同。 - Paiku Han
我尝试反转正确的PNG文件中的字节顺序,结果得到了与您相同的错误结果:文件:gray-wrong_endian.png(118字节) 在偏移量0x0000c处的块IHDR,长度为218103808:读取数据时遇到EOF - Glenn Randers-Pehrson
@PaikuHan:我链接中的任何答案都应该同样有效。对于这样一个简单的任务,我通常使用被接受的答案中的方法——手动移位比特。这几乎不值得编写一个函数,宏可以很好地工作。 - Jongware
1
@PaikuHan 我不是在询问我的代码出了什么问题。我只是同意jongware的观点,即问题在于你的字节顺序,并通过交换一个好的文件的字节顺序来验证我的答案,得到了与你相同的错误答案。在libpng中有宏/函数可以按正确的字节顺序从PNG数据流中读取长整型。请参见pngread.c中的png_get_uint_32(我知道你没有使用libpng,但它是开源的,如果你想的话,可以将这些宏复制到你自己的代码中)。 - Glenn Randers-Pehrson
@GlennRanders-Pehrson 好的,抱歉我误解了。不过我会检查一下libpng的代码。我有一种感觉这将是一次有趣的阅读。 - Paiku Han
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接