开发者

libpng size of png

My program reads from a data stream of ind开发者_如何学编程eterminate length. When it reads a PNG file it needs to store it for later and not decode it. Does libpng provide any function for providing the size of the PNG so it knows how many bytes to store?

If it does not, do I have to write my own PNG chunk parser to skip through the chunks until the ending chunk? I figured that I might as well include CRC verification, but it seems very complicated, which is why I was hoping libpng would provide a way to do this transparently.


The short answer is NO. Libpng doesn't even return the length of the individual chunks, so if you are using libpng you do indeed have to skip through all the chunks to find the end of the PNG datastream.

The reason libpng doesn't return chunk lengths is that libpng is designed for streaming, so it does not necessarily know how long your datastream of indeterminate length is going to be. All it knows is the length of the chunk whose header it has already read.

You can use "pngcheck" to read a PNG file and produce a list of chunks with their lengths. See http://www.libpng.org/pub/png/apps/pngcheck.html‎ Pngcheck is open source, so you can adapt it to your own needs.


This might be very stupid, but if you don't need to decode the PNG, why not forget that it's PNG, and just store it by allocating a fixed minimal amount of memory and doubling the allocated size as you go with realloc?


This is a simple PNG chunk-dumper. It doesn't attempt CRC verification or storing the data for the chunks, but should give at least some general notion of how to read through the chunks. Warning: this is just something I whipped together in a hurry and have never had a need to upgrade, so it's not an example of the cleanest code ever, by any stretch of the imagination. It does, however, verify that the file contains at least some of the correct signatures for a PNG file, and display the dimensions of the image contained in the file.

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜