libpng размер png - PullRequest
       8

libpng размер png

2 голосов
/ 23 апреля 2011

Моя программа читает из потока данных неопределенной длины. Когда он читает файл PNG, он должен сохранить его на потом и не декодировать. Предоставляет ли libpng какую-либо функцию для указания размера PNG, чтобы она знала, сколько байт хранить?

Если этого не произойдет, должен ли я написать свой собственный синтаксический анализатор фрагментов PNG, чтобы пропустить фрагменты до конечного фрагмента? Я подумал, что мог бы также включить проверку CRC, но это кажется очень сложным, поэтому я надеялся, что libpng предоставит способ сделать это прозрачно.

Ответы [ 3 ]

1 голос
/ 24 апреля 2011

Краткий ответ - НЕТ. Libpng даже не возвращает длину отдельных чанков, поэтому если вы используете libpng, вам действительно нужно пропустить все чанки, чтобы найти конец потока данных PNG.

Причина, по которой libpng не возвращает длины фрагментов, заключается в том, что libpng предназначен для потоковой передачи, поэтому он не обязательно знает, как долго будет длиться ваш поток данных неопределенной длины. Все, что он знает, - это длина фрагмента, заголовок которого он уже прочитал.

Вы можете использовать "pngcheck", чтобы прочитать файл PNG и создать список фрагментов с их длинами. См. http://www.libpng.org/pub/png/apps/pngcheck.html‎ Pngcheck с открытым исходным кодом, так что вы можете адаптировать его под свои нужды.

0 голосов
/ 23 апреля 2011

Это может быть очень глупо, но если вам не нужно декодировать PNG, почему бы не забыть, что это PNG, и просто сохранить его, выделяя фиксированный минимальный объем памяти и удваивая выделенный размер по мере использования realloc * * 1002

0 голосов
/ 23 апреля 2011

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