【问题标题】:C++ PNG header missread IHDR data chunk length, width and heightC++ PNG 标头误读 IHDR 数据块长度、宽度和高度
【发布时间】:2014-04-20 03:46:27
【问题描述】:

我正在尝试为一个类创建一个方法,该方法只读取 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;
}

打印出来的结果是这样的(控制台上明显没有显示cmets):

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 网站上所写的那样; (数据块的)长度值存储在 "A four-byte unsigned integer" 中。图像的the width and height 也是如此。所以我也尝试了 unsigned int 和 unsigned short ,但似乎没有任何效果。

即使我使用了 printfs(我不知道如何使用 cout 将字符格式化为整数),但如果可能的话,我正在寻找 C++ 解决方案。

谢谢

【问题讨论】:

    标签: c++ png


    【解决方案1】:

    您的机器或编译器使用相反的顺序来存储多字节值。

    请参阅同一参考中的“7.1 整数和字节顺序”:

    所有需要多于一个字节的整数都应按网络字节顺序排列...

    然后是一个说明它的图表。

    要为您的字节数获取正确的值,请使用预定义函数之一(我不记得哪个函数做了什么;请阅读How do you write (portably) reverse network byte order?)或编写您自己的函数来反转它们。

    您的样本值218103808 在以十六进制打印时显示0xD000000;反转字节会产生正确的预期结果0xD13

    【讨论】:

    • 我使用了gcc。因为您提供的链接中的那个(如果确实交换了字节)给了我与非交换字节版本相同的结果。
    • 我尝试在正确的 PNG 中反转字节顺序并得到与您相同的错误结果:文件:gray-wrong_endian.png(118 字节)块 IHDR,偏移量 0x0000c,长度 218103808:EOF 而读取数据
    • @PaikuHan:我的链接中的任何答案都应该有效。对于这样一个简单的任务,我通常使用公认答案中的方法——手动移位。几乎不值得为其编写函数,宏可以正常工作。
    • @Jongware 好吧,我尝试了接受的答案,但它没有用......这就是我选择 gcc 函数的原因,因为我知道/现在知道问题在于字节顺序。跨度>
    • @PaikuHan 我不是在问我的代码出了什么问题。我只是同意 jongware 的问题在于您的字节顺序,并通过交换好文件的字节顺序来验证我的答案以获得与您得到的相同错误答案。 libpng 中有宏/函数可以以正确的字节顺序从 PNG 数据流中读取长整数。请参阅 pngread.c 中的 png_get_uint_32(我知道您没有使用 libpng,但它是开源的,如果您愿意,可以将宏复制到自己的代码中)。
    猜你喜欢
    • 2012-12-14
    • 1970-01-01
    • 2017-02-26
    • 1970-01-01
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    相关资源
    最近更新 更多