libpng size of png

為{幸葍}努か 提交于 2019-12-01 09:38:05

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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!