【问题标题】:How to find the end of a DEFLATE block如何找到 DEFLATE 块的结尾
【发布时间】:2020-08-26 23:40:41
【问题描述】:

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

【问题讨论】:

  • 不只是IDAT的大小吗?
  • @yao99 根据我对文档的理解,我认为一个 IDAT 块中可以有多个 deflate 块

标签: c++ zlib deflate


【解决方案1】:

根据PNG Deflate/Inflate Compression 文档

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

...

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

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

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

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

每个块都使用 LZ77 算法和 Huffman 编码的组合进行压缩。每个块的霍夫曼树独立于前一个或后一个块的霍夫曼树; LZ77 算法可能使用对出现在前一个块中的重复字符串的引用,之前最多 32K 输入字节。

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

压缩数据中的每种类型的值(文字、距离和长度)都使用 Huffman 代码表示,文字和长度使用一个代码树,距离使用单独的代码树。每个块的代码树以紧凑的形式出现在该块的压缩数据之前。

因此,要确定给定块的结尾,您必须解析块的霍夫曼代码以了解压缩数据中每个元素的位置和类型,然后您可以根据需要处理每个元素,直到找到块中最后一个元素的结尾。第 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 添加到输出流中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    • 2018-01-05
    • 2019-05-27
    • 2014-12-09
    • 2013-01-25
    • 2015-06-23
    • 2013-08-21
    相关资源
    最近更新 更多