使用inflate解压缩png文件

时间:2017-03-20 22:26:26

标签: c++ c png zlib inflate

我在解压缩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只是一个包含图像宽度,高度和深度的结构,并且有一个大小为{的unsigned char数组{1}}。

我尝试解压缩的图片是:arial.png

它没有过滤(0)并且是带有alpha的truecolor png。它也只包含一个IDAT块。

但我得到的是这样的东西:incorrect png

我意识到图像是颠倒的,这是我的渲染器自下而上,png是自上而下的问题;它不是我现在关心的事情。

我还应该注意width*height*depth实际只运行一次并返回Z_OK,所以我不认为问题在于不处理扫描线过滤器。我尝试过每行添加一个字节,然后不将每行的第一个字节复制到inflate数组,但这并没有太大的区别。

任何想法我可能做错了什么?

3 个答案:

答案 0 :(得分:0)

看起来您可能忽略了每条扫描线开头的过滤器方法字节。它就在那里,即使它是0。

答案 1 :(得分:0)

我认为你应该成功while(Stream.avail_out == 0);

只要z.avail_out等于零,就意味着压缩数据的压缩数据填充字节和inflate()需要再次调用。

总是想到它的含义,当有可用(未填充)的字节输出时,我们应该停止avail_out > 0

答案 2 :(得分:0)

首先,在最后一次通话中返回Z_OK是不行的。如果它没有返回Z_STREAM_END,那么您没有解压缩并验证完整的压缩数据。

其次,您的avail_out不允许每条扫描线开头的滤波器字节。将高度添加到avail_out并为其提供空间。

第三,我不知道你是如何从原始512x512 RGBA图像中获得643x514 RGB图像的。你需要跳过每一行的滤波器字节,然后每个像素四个字节。