Использование inflate для распаковки png файла

У меня были проблемы с распаковкой файла png. Это код, который обрабатывает блок IDAT:

case PNG_CHUNK_IDAT: {
z_stream Stream = {};
int Error = inflateInit(&Stream);

if(Error == Z_OK) {
Stream.avail_in = ChunkLength;
Stream.next_in = At;
Stream.avail_out = PngImage.Width * PngImage.Height * PngImage.Depth;
Stream.next_out = PngImage.Pixels;

do {
Error = inflate(&Stream, Z_NO_FLUSH);
if(Error != Z_OK) {
break;
}
} while(Stream.avail_out != 0);
inflateEnd(&Stream);
}

At += ChunkLength;
break;
}

куда At текущая позиция в буфере файла png, и PngImage это просто структура, которая содержит ширину, высоту и глубину изображения и имеет массив без знака размера width*height*depth,

Изображение, которое я пытаюсь распаковать, выглядит так: arial.png

Он не имеет фильтрации (0) и является полноцветным png с альфа-каналом. Он также содержит только один блок IDAT.

Но вместо этого я получаю что-то вроде этого: неверный png

Я знаю, что изображение переворачивается вверх ногами, это проблема моего рендерера снизу вверх и png сверху вниз; это не то, что меня сейчас волнует.

Я должен также отметить, что inflate только на самом деле запускается один раз и возвращает Z_OK, поэтому я не думаю, что проблема в том, что не обрабатываются фильтры линии сканирования. Я попытался добавить один байт на строку, а затем не копировать первый байт каждой строки в Pixelsмассив, но это не имело большого значения.

Есть идеи, что я могу делать не так?

0

Решение

Во-первых, возвращаясь Z_OK на последнем звонке не ок. Если не вернется Z_STREAM_END, то вы не распаковали и не проверили полные сжатые данные.

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

В-третьих, я понятия не имею, как вы получили изображение RGBA 643×514 из исходного изображения RGBA 512×512. Вам нужно пропустить байт фильтра в каждой строке, а затем каждый пиксель четыре байт.

0

Другие решения

Похоже, вы можете игнорировать байт метода фильтра в начале каждой строки развертки. Это там, даже если это 0.

0

Я думаю, ты должен сделать это while(Stream.avail_out == 0);

Пока, z.avail_out равен нулю, это означает, что сжатые данные заполнены байтами, доступными для распакованных данных и inflate() нужно позвонить снова.

Всегда думайте о его значении, мы должны остановиться, когда есть доступные (не заполненные) байты для вывода, чтобы avail_out > 0,

0