libpng size of png

前端 未结 3 565
夕颜
夕颜 2021-01-15 14:06

My program reads from a data stream of indeterminate length. When it reads a PNG file it needs to store it for later and not decode it. Does libpng provide any function for

相关标签:
3条回答
  • 2021-01-15 14:30

    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?

    0 讨论(0)
  • 2021-01-15 14:41

    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 讨论(0)
  • 2021-01-15 14:45

    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.

    0 讨论(0)
提交回复
热议问题