libpng大小为png

时间:2011-04-23 05:19:26

标签: c libpng

我的程序从不确定长度的数据流中读取。当它读取PNG文件时,需要将其存储以供以后使用而不对其进行解码。 libpng是否提供了提供PNG大小的任何功能,因此它知道要存储多少字节?

如果没有,我是否必须编写自己的PNG块解析器以跳过块直到结束块?我认为我可能还包括CRC验证,但它看起来非常复杂,这就是为什么我希望libpng能提供一种透明地完成此任务的方法。

3 个答案:

答案 0 :(得分:1)

简短的回答是否定的。 Libpng甚至没有返回单个块的长度,所以如果你使用libpng,你确实必须跳过所有块来找到PNG数据流的末尾。

libpng没有返回块长度的原因是libpng是为流式传输而设计的,因此它不一定知道不确定长度的数据流的长度。它所知道的是它已经读过的标题的长度。

您可以使用“pngcheck”读取PNG文件并生成长度为的块列表。请参阅http://www.libpng.org/pub/png/apps/pngcheck.html Pngcheck是开源的,因此您可以根据自己的需要进行调整。

答案 1 :(得分:0)

这是一个简单的 PNG块式转储程序。它不会尝试CRC验证或存储块的数据,但至少应该给出如何读取块的一般概念。警告:这只是我匆忙拼凑起来并且从未需要升级的东西,所以它不是任何一段时间内最干净的代码的例子。但是,它确实验证该文件至少包含PNG文件的一些正确签名,并显示文件中包含的图像的尺寸。

#include <iostream>
#include <fstream>
#include <winsock.h>
#include <algorithm>
#pragma comment(lib, "ws2_32.lib")

typedef unsigned int uint32_t;

bool file_header(std::istream &in) { 
    unsigned char buffer[8];
    static const unsigned char valid[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
    in.read((char *)&buffer, sizeof(buffer));
    return std::mismatch(buffer, buffer+sizeof(buffer), valid).first == buffer+sizeof(buffer);
}

long read_net_long(std::istream &in) { 
    long temp;
    in.read((char *)&temp, sizeof(temp));
    return ntohl(temp);
}

bool is_iend(std::istream &in) { 
    uint32_t length;
    char sig[5] = {0};
    char iend[5] = "IEND";
    uint32_t CRC;

    length = read_net_long(in);

    in.read((char *)&sig, 4);
    in.ignore(length);
    CRC = read_net_long(in);
    std::cout << "found: " << sig << ", length = " << length << "\n";
    return std::mismatch(sig, sig+sizeof(sig), iend).first == sig+sizeof(sig);
}

#pragma pack(push, 1)

class ihdr {
    uint32_t signature;
    uint32_t length;
    uint32_t width;
    uint32_t height;
    unsigned char depth;
    unsigned char color_type;
    unsigned char compression_method;
    unsigned char filter_method;
    unsigned char interlacing;
    uint32_t CRC;
public:

    friend std::istream &operator>>(std::istream &is, ihdr &h) {
        is.read((char *)&h, sizeof(h));

        if (h.signature != 218103808)
            std::cerr << "Invalid chunk: " << h.signature << "\n";
        h.width = ntohl(h.width);
        h.height = ntohl(h.height);
        return is;
    }

    friend std::ostream &operator<<(std::ostream &os, ihdr const &h) {
        return std::cout << "width: " << h.width << ", height: " << h.height << "\n";
    }
};
#pragma pack(pop)

void dump_ihdr(std::istream &in) {
    ihdr header;

    in >> header;
    std::cout << header;
}

int main(int argc, char **argv) { 
    if (argc != 2) {
        std::cerr << "Usage: read_png <png_file>";
        return 1;
    }

    std::ifstream in(argv[1], std::ios::binary);

    std::cout << argv[1] << "\n";
    if (file_header(in)) {
        dump_ihdr(in);
        while (!is_iend(in))    
            if (!in) {
                std::cout << "Reached EOF without finding IEND chunk\n";
                return 1;
            }
    }
    else {
        std::cout << "Didn't find a PNG header\n";
        return 1;
    }
    return 0;
}

答案 2 :(得分:0)

这可能非常愚蠢,但如果您不需要解码PNG,为什么不忘记它是PNG,只需通过分配固定的最小内存量并将分配的大小加倍来存储它{ {1}}?