使用 inflate 解压缩 png 文件
Using inflate to decompress a png file
我在解压缩 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) 并且是带有 alpha 的真彩色 png。它还只包含一个 IDAT 块。
但是我得到的是这样的:incorrect png
我知道图像颠倒了,这是我的渲染器自下而上和 png 自上而下的问题;这不是我现在关心的事情。
我还应该注意 inflate
实际上只运行一次 return Z_OK,所以我认为问题不在于没有处理扫描线过滤器。我试过每行添加一个字节,然后不将每行的第一个字节复制到 Pixels
数组,但这并没有太大的区别。
知道我做错了什么吗?
看起来您可能忽略了每条扫描线开头的过滤方法字节。它就在那里,即使它是 0。
我认为你应该做到 while(Stream.avail_out == 0);
只要z.avail_out
为零,就表示压缩后的数据填充了可供解压数据使用的字节,inflate()
需要重新调用
总是想到它的意思,当有可用(未填充)字节输出时我们应该停止这样 avail_out > 0
.
首先,在最后一次调用时 returning Z_OK
不正常。如果没有returnZ_STREAM_END
,说明你没有解压验证完整的压缩数据
其次,您的 avail_out
不允许在每个扫描行的开头使用过滤字节。将高度添加到 avail_out
并为其留出空间。
第三,我不知道你是如何从原始的 512x512 RGBA 图像中得到一个 643x514 RGB 图像的。你需要跳过每一行的过滤器字节,然后每个像素是四个字节。
我在解压缩 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) 并且是带有 alpha 的真彩色 png。它还只包含一个 IDAT 块。
但是我得到的是这样的:incorrect png
我知道图像颠倒了,这是我的渲染器自下而上和 png 自上而下的问题;这不是我现在关心的事情。
我还应该注意 inflate
实际上只运行一次 return Z_OK,所以我认为问题不在于没有处理扫描线过滤器。我试过每行添加一个字节,然后不将每行的第一个字节复制到 Pixels
数组,但这并没有太大的区别。
知道我做错了什么吗?
看起来您可能忽略了每条扫描线开头的过滤方法字节。它就在那里,即使它是 0。
我认为你应该做到 while(Stream.avail_out == 0);
只要z.avail_out
为零,就表示压缩后的数据填充了可供解压数据使用的字节,inflate()
需要重新调用
总是想到它的意思,当有可用(未填充)字节输出时我们应该停止这样 avail_out > 0
.
首先,在最后一次调用时 returning Z_OK
不正常。如果没有returnZ_STREAM_END
,说明你没有解压验证完整的压缩数据
其次,您的 avail_out
不允许在每个扫描行的开头使用过滤字节。将高度添加到 avail_out
并为其留出空间。
第三,我不知道你是如何从原始的 512x512 RGBA 图像中得到一个 643x514 RGB 图像的。你需要跳过每一行的过滤器字节,然后每个像素是四个字节。