我的程序从不确定长度的数据流中读取。当它读取PNG文件时,需要将其存储以供以后使用而不对其进行解码。 libpng是否提供了提供PNG大小的任何功能,因此它知道要存储多少字节?
如果没有,我是否必须编写自己的PNG块解析器以跳过块直到结束块?我认为我可能还包括CRC验证,但它看起来非常复杂,这就是为什么我希望libpng能提供一种透明地完成此任务的方法。
答案 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}}?