首页 > 解决方案 > 在 Python 中正确实现 ArchiveLib 压缩

问题描述

我写了一个刺绣输入和输出 python 模块EmbroidePy/pyembroidery和 HUS 和 VIP 是两种相关的、旧的和流行的刺绣格式,它们使用特定的失效压缩格式,特别是ArchiveLib, AL_GREENLEAF_LEVEL_4. 许多刺绣软件套件使用旧的 .dll 文件al21mfc.dll来利用正确的压缩。包含 .dll 文件是不可能的,但似乎没有任何合理的方法可以无缝模拟失效的压缩格式。

Embroidermodder Team 有一个可以接受的 C++ 刺绣读写库,它实际上在本地实现了这一点,emb-compress,我也想做同样的事情。

我希望本机能够在 python 中,也许在 Java 中压缩和解压缩这些元素。我更喜欢可读的代码,但这不是远程要求。

但是,有问题。

解决方案不需要很漂亮。解决方案不需要很快。我考虑过诸如将 C++ 代码编译成某种在 python 中实现虚拟 CPU 的字节码。或者用另一个会增加乱码级别的程序移植看起来乱码的代码,或者手动完成(但它总是很快就让我迷失了)。我在网络最黑暗的角落寻找原始源代码。而且我做得很短。

似乎应该有足够的东西让一些东西发挥作用,但每个想法似乎都比下一个更难,更不实用。有什么我遗漏的东西或一些可以快速使这些解决方案之一起作用的想法吗?或者其他可行的解决方案?

标签: pythoncompression

解决方案


ArchiveLib 压缩是进行 ARJ 压缩的 Robert Jung 的转授权产品。在 ARJ 和 ArchiveLib 中使用了相同的方案,并且专利保护已经过期。

它发送通过读取 n huffman_code_length 构建的压缩霍夫曼表。检查这些是否解决了平衡的霍夫曼树。这些是从最长的代码字到最短的代码字排序的,绑定的条目到最低值。

因此,如果值的长度是 4、8、2、2。它给出这些 8、4、2、2 和代码字 0、10、110、111。这些给出的顺序反映了它们的位置。所以第一个条目得到 10,第二个 0,第三个 110 和第四个 111。由于这两个并列,它们按收到的顺序应用。

块按 16 个字节读取以传达符号的数量。后面是字符长度表,这是霍夫曼编码的。然后使用字符长度表来构建字符表。使用霍夫曼表构建字符霍夫曼表。然后发送第三个距离表,它给出窗口内的回溯值以供读取。


字符长度表。

5 位计数数据。这可以传达 0 到 32 个条目的值。如果为零,则读取另一个 5 位值,用于所有值。

对于计数中的每个值,我们读取一个可变长度。索引 3 处的特殊值(给定的第 4 个值)以 2 位为前缀,在索引中向前跳过 0 到 3 个值。这些跳过的值被视为计数的一部分。这前三个条目是字符表中的特殊命令代码。

然后,这将提供多达 32 个不同的值长度,霍夫曼代码长度可以是。


字符表。

9 位计数。这意味着它可以提供从 0 到 511 的值。如果为 0,则所有值都是紧随其后的 9 位。

条目数是实际填充表格的值。所以如果 4 那么我们将在 511 条目表中有 4 个不同的非零条目。

编码的数据是如何跳过或填充提供的相关数据。0 表示我们在表格序列中设置了一个零。1 表示我们读取 4 位并将该值加 3 并将那么多表条目归零。2 表示我们读取 9 位并将该值加 20 并将那么多表条目归零。对于任何大于该值的值,我们减去 2 并将其简单地放入表中。

结果是一个包含最多 511 个元素的所有必需代码的长度列表(任何没有得到值的条目都是 0)。然后将其发送到霍夫曼表构建算法以检查有效性并构建表。这会将霍夫曼代码分配给从 0 到 511 的令牌。


距离霍夫曼

5 位计数。如果为零,则为所有值给出后续 5 位数字。

每个条目读取一个可变长度的数据值。这会产生一些长度的 0-32 值。然后将这些用于构建相关的霍夫曼表。

该表将有多达 32 个由霍夫曼表定义的不同整数值。


可变长度数据。

3位值。如果不是 7,则返回该值。如果 7 读取 0 到 13 个额外字节,直到找到非 1 值。因此,如果一个值小于 7,则使用该值。如果大于 7,则每增加 1 表示值大 1。所以 11110 是 8。111110 是 9。最多 13 位。这给出了从 0 到 20 的值。在 3 到 16 位之间。


减压。

实际解压意味着读取块和表。然后使用字符表压缩流,并在需要时使用距离表。对照字符表检查每个值以提供令牌。如果值为 0-255,则为文字。如果值为 510,则表示结束命令。如果该值大于 255,则它对应于指向窗口的指针。大于 255 的值对应于 (v - 253) 个字符的字符串。也就是说,值为 256 意味着我们正在从窗口中读取 3 个字符。257 表示 4 个字符。最多 509,这意味着我们正在从窗口中读取 255 个字符。如果我们从查找中读取 a ,则流上的下一个值是使用距离 Huffman 表读取的向后距离。


压缩。

任何适合解压缩方案的压缩方案都可以工作。它如何找到编码的东西是无关紧要的。ARJ 的专利只是简单的如何快速压缩东西的方式,这不是什么大问题。然而,一个有趣的方法是根本不压缩东西,而只是通过标题强制执行一个空操作。

编写空操作压缩的示例。

16 位块大小。如果我们需要超过 32k 个元素,我们将不得不编写另一个块。

  • 写字符长度霍夫曼。5 个字节:00000,我们有 0 个条目。1个长度。它们都是8。5个字节:01010,所有值都是10,意思是长度8。

字符长度霍夫曼只返回 10。

  • 写作字符霍夫曼。9 位:100000000,256 个条目。

所有条目都会查询 Character Length huffman 并获得值 10,即 8。

Character Huffman 表将有 256 个 8 位条目。这将构建一个文字表,其中每个字节都完全等于它自己。由于有 256 个并列条目,它们首先被放在最低元素中。

距离霍夫曼。(我们从不使用它)。5 位:00000 无条目。5 位:00000 任何值都没有关系。

这使得编写我们的文字表需要 29 位。但是,为了使这种方法非常有用,我们希望它准确地划分 8 位。我们可以通过改变距离哈夫曼来做到这一点,因为所有值都是文字,所以我们从不使用它。

5 位:00001 1 距离霍夫曼。3 位:111 我们有一个可变长度值 7 或更大。5 位:11110 我们在这个 7 上加上 4,长度为 11。但实际上我们是在填充。

(10) + (9) + (5 + 3 + 5) = 32 位。

0b00000010101000000000000111111110 这可以存储在一个整数中:0x02A001FE

所以compress我们可以简单地给出块的大小,然后是0x02A001FE我们的未压缩数据。它将被视为压缩。因为我实际上不能推荐使用大多数死压缩方案。


推荐阅读