Это простой 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;
}