微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何找到DEFLATE块的结尾

如何解决如何找到DEFLATE块的结尾

出于自我教育的目的,我正在尝试创建一个程序,该程序会将png文件转换为RGBA值数组。但是我在解码使用delate格式用zlib编码的IDAT部分时遇到问题。我遇到的问题是我不知道如何找到压缩块的末尾。在文档中唯一显示长度的地方只是用于解压缩的块,但是对于具有认霍夫曼表和提供的霍夫曼表的块,似乎并不是找出块结束位置的方法。我应该如何以deflate格式查找块的结尾。

解决方法

根据PNG Deflate/Inflate Compression文档

zlib数据流中的压缩数据存储为一系列块,每个块可以代表原始(未压缩)数据,使用固定Huffman码编码的LZ77压缩数据或使用自定义Huffman码编码的LZ77压缩数据。 最后一块中的标记位将其标识为最后一块,从而使解码器能够识别压缩数据流的结尾。有关压缩算法和编码的更多详细信息,请参见deflate规范[RFC-1951]

...

在PNG文件中,所有IDAT块的内容的串联构成了如上所述的zlib数据流。如本文档其他地方所述,此数据流将解压缩为经过过滤的图像数据。

需要强调的是,IDAT块之间的边界是任意的,并且可以落在zlib数据流中的任何位置。 IDAT块边界和缩小块边界或zlib数据的任何其他特征之间不一定存在任何关联。例如,完全有可能在IDAT块之间拆分终止zlib检查值。*“

并且根据RFC 1951:“ DEFLATE压缩数据格式规范版本1.3”:

压缩数据集由一系列块组成,这些块对应于输入数据的连续块。 块大小是任意的,除了不可压缩的块限制为65,535个字节。

使用LZ77算法和霍夫曼编码的组合来压缩每个块。每个块的霍夫曼树独立于先前或后续块的霍夫曼树。 LZ77算法可以使用对在先前块中出现的重复字符串的引用,直到之前的32K输入字节为止。

每个块由两部分组成:一对描述压缩数据部分表示形式的霍夫曼代码树和一个压缩数据部分。(霍夫曼树本身使用霍夫曼编码进行压缩。 )压缩数据由一系列两种类型的元素组成:文字字节(在先前的32K输入字节中未被检测为重复的字符串)和指向重复字符串的指针,其中指针表示为对。 “压缩”格式中使用的表示形式将距离限制为32K字节,将长度限制为258字节,但不限制块的大小,除了不可压缩的块(如上所述)受到限制。

使用霍夫曼代码表示压缩数据中的每种值类型(文字,距离和长度),其中一个代码树用于文字和长度,而一个代码树用于距离。每个块的代码树以紧凑的形式出现在该块的压缩数据之前。

因此,要确定给定块的结尾,您必须分析该块的霍夫曼代码,以了解压缩数据中每个元素的位置和类型,然后可以根据需要处理每个元素,直到找到块中最后一个元素的结尾。第3.2节详细介绍了如何压缩块的格式,尤其是Section 3.2.3

3.2.3。块格式的详细信息

每个压缩数据块都以3个标头位开头,这些标头位包含以下数据:

first bit       BFINAL
next 2 bits     BTYPE

请注意,标头位不必一定在字节边界上开始,因为一个块不必占用整数字节。

仅当这是数据集的最后一块时,才设置BFINAL。

BTYPE指定如何压缩数据,如下所示:

00 - no compression
01 - compressed with fixed Huffman codes
10 - compressed with dynamic Huffman codes
11 - reserved (error)

这两种压缩情况之间的唯一区别是,如何为文字/长度和距离字母定义霍夫曼代码。

在所有情况下,实际数据的解码算法如下:

do
    read block header from input stream.
    if stored with no compression
        skip any remaining bits in current partially
            processed byte
        read LEN and NLEN (see next section)
        copy LEN bytes of data to output
    otherwise
        if compressed with dynamic Huffman codes
            read representation of code trees (see
                subsection below)
        loop (until end of block code recognized)
            decode literal/length value from input stream
            if value < 256
                copy value (literal byte) to output stream
            otherwise
                if value = end of block (256)
                    break from loop
                otherwise (value = 257..285)
                    decode distance from input stream

                    move backwards distance bytes in the output
                    stream,and copy length bytes from this
                    position to the output stream.
        end loop
while not last block

请注意,重复的字符串引用可能引用前一个块中的字符串。即,后向距离可以跨越一个或多个块边界。但是,距离不能超过输出流的开头。 (使用预设字典的应用程序可能会丢弃输出流的一部分;无论如何,距离都​​可以引用输出流的那一部分)。还要注意,引用的字符串可能与当前位置重叠;例如,如果解码的最后2个字节具有值X和Y,则的字符串引用会将X,Y,X,Y,X添加到输出流。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。