【问题标题】:Parsing GIF Raster Data - LZW解析 GIF 栅格数据 - LZW
【发布时间】:2012-12-21 15:23:56
【问题描述】:

我一直在尝试在 PHP 中解压缩 GIF,似乎除了 LZW 解压缩之外的一切都已关闭。我保存了显示的图像:

这张图片是这样的 3 x 5:

Blue  Black Black
Black Blue  Black
Black Black Black
White White White
White White White

我决定在 Binary 中手动完成并解析这个文件。手动解析的结果如下。我仍然对如何在这里解码栅格数据感到困惑。有人可以分解栅格数据如何成为图像吗?我已经能够分解一张图片,但没有别的(不是这张图片)。我已经发表了我对这应该如何分解的理解,但我显然做错了。

01000111 G
01001001 I
01000110 F
00111000 8
00111001 9
01100001 a

Screen Descriptor
WIDTH
00000011 3
00000000

00000101 5
00000000

10010001 GCM (1), CR (001), BPP (001), CD = 2, COLORS = 4

00000000 BGCOLOR Index

00000000 Aspect Ratio

GCM
BLUE
00110101 | 53
00000000 | 0
11000001 | 193

WHITE
11111111 | 255
11111111 | 255
11111111 | 255

BLACK
00000000 | 0
00000000 | 0
00000000 | 0

00000000 | 0
00000000 | 0
00000000 | 0

Extension
00100001 | 21
Function Code
11111001 | F9
Length
00000100 | 4
00000000
00000000
00000000
00000000
Terminator
00000000

Local Descriptor
00101100 Header
XPOS
00000000 | 0
00000000

YPOS
00000000 | 0
00000000

Width
00000011 | 3
00000000

Height
00000101 | 5
00000000

Flags
00000000 (LCM = 0, Interlaced = 0, Sorted = 0, Reserved = 0, Pixel Bits = 0)

RASTER DATA
Initial Code Size
00000010 | 2
Length
00000101 | 5

Data
10000100
01101110
00100111
11000001
01011101

Terminator
00000000

00111011 | ;
00000000

我的尝试

10000100
01101110
00100111
11000001
01011101

初始代码大小 = 3 一次读取 2 位

10
00
Append last bit to first (010)
String becomes 010 or 2. 2 would be color # 3 or BLACK

在这一点上,我已经错了。第一种颜色应该是蓝色。

我一直在使用的资源:

http://www.daubnet.com/en/file-format-gif http://en.wikipedia.org/wiki/Graphics_Interchange_Format http://www.w3.org/Graphics/GIF/spec-gif87.txt

【问题讨论】:

  • 好的,抱歉,但我只想问...为什么?
  • 我需要能够将 GIF 动态转换为打印机图像格式 (PCX / GRF) 我已经知道如何进行这些转换,但不是从 GIF。
  • 作为替代方案,我还想指出 imagemagick 非常强大,并且很可能也会为你做到这一点:) 不过有趣的问题
  • imagemagick 不支持 GRF,这确实是我的最终目标。我相信 GRF 是一种 Zebra 打印机格式。
  • 我现在没有,但它看起来像这样:barcodegiant.com/zebra/… 发送到打印机的代码在 ZPL2 中

标签: algorithm gif decoding lzw


【解决方案1】:

GIF 解析器

您说您想编写自己的 GIF 解析器以了解其工作原理。我建议您查看任何包含 GIF 阅读器的库的源代码,例如事实上的参考实现 GIFLIB。相关源文件为dgif_lib.c;开始at slurp进行解码,或者跳转到LZW decompression implementation

这是您的图像的解码方式。

我认为问题在于您错误地将输入字节拆分为 LZW 代码。

颜色数量为(0b001 + 1) * 2 = 4

代码大小从 2 + 1 = 3 位开始。

所以最初的字典是

000 = color 0 = [blue]
001 = color 1 = [white]
010 = color 2 = [black]
011 = color 3 = [black]
100 = clear dictionary
101 = end of data

现在,GIF packs LZW codes into bytes in LSB-first order. 因此,第一个代码存储为第一个字节的 3 个最低有效位;第二个代码作为接下来的 3 位;等等。在您的示例中(第一个字节:0x84 = 10000100),前两个代码是100(透明)和000(蓝色)。整件事

01011101 11000001 00100111 01101110 10000100

被分成代码(读取最高3位代码后切换到4位组,111)为

0101 1101 1100 0001 0010 0111 0110 111 010 000 100

这解码为:

     last
code code
 100      clear dictionary
 000      output [blue] (1st pixel)
 010  000 new code in table:
              output 010 = [black]
              add 110 = old + 1st byte of new = [blue black] to table
 111  010 new code not in table:
              output last string followed by copy of first byte, [black black]
              add 111 = [black black] to table
              111 is largest possible 3-bit code, so switch to 4 bits
0110 0111 new code in table:
              output 0110 = [blue black]
              add 1000 = old + 1st byte of new = [black black blue] to table
0111 0110 new code in table:
              output 0111 = [black black]
              add 1001 = old + 1st byte of new = [blue black black] to table
...

所以输出开始(包装到 3 列):

blue  black black
black blue  black
black black ...

这就是你想要的。

【讨论】:

  • 这就是我要找的。除了 lsb 之外,我在一次尝试中都获得了减压权。我在规范中看到了小端字节顺序,但由于某种原因我没有看到它适用于栅格数据。 (我可以奖励赏金前 18 小时)
【解决方案2】:

这个网站是一个关于 GIF 格式的优秀资源,并且对 LZW 压缩和解压缩过程提供了很好的解释:

http://www.matthewflickinger.com/lab/whatsinagif/index.html

【讨论】:

    【解决方案3】:

    无需编写自己的 GIF 阅读器的解决方案

    除了你自己的启迪之外,试试这个。

    一些注意事项

    • 您的 GIF 文件是 GIF89a。您链接到 GIF87a 规范; 89a specification is here
    • 您似乎担心使用库来解析图像会损害性能。这是没有意义的。这些库通常以优化的 C 语言实现;您的手动解决方案将使用 PHP(一种解释性语言)编​​写。
    • 您提到了 PCX,imagemagick 等库确实支持这些库。

    或者只使用PNG

    根据ZPL 2 programming manual,支持PNG。例如,~DY(下载图形)命令采用b(格式)参数,其中P(PNG)是一个选项,除了默认的GRF。另见Printing PNG images to a zebra network printer

    很多 库可以将 GIF 转换为 PNG。你可以使用ImageMagick (PHP binding),或者只使用PHP函数imagecreatefromgifimagepng

    【讨论】:

    • 赏金的重点是如何进行解压。我查看了源文件,包括您提到的源文件,但我仍然无法解压。无论优化等如何,这些响应都没有回答实际问题。
    • @Tom:你还没有解释为什么你需要自己解压。
    • 原因无所谓。我想知道它是怎么做的。
    • @Tom:我认为您错误地将字节字符串拆分为 LZW 代码。添加为单独的答案,因为它是一种不同的方法。
    【解决方案4】:

    我无法帮助您进行 LZW 解码,但是使用 PHP GD 扩展中的 imagecreatefromgif() 之类的库函数来解析 GIF 文件并提取图像数据会不会更容易,您可以然后转换成你的目标格式?

    【讨论】:

    • 我可以在用 PHP 的 GD 解析后遍历每个像素来解析它,但这会增加额外的开销。我也想知道怎么做,以便以后可以使用。我在网上看到的所有内容都缺少解释中的小关键点,并且有些不一致。
    • 它可能仍然与在 PHP 中手动进行 LZW 解压一样快。此外,我相信其他一些 PHP 图像处理扩展可以更好地访问栅格数据。
    【解决方案5】:

    很高兴您想知道如何在不使用其他人编写的库的情况下进行 LZW。 LZW 不会逐像素解码图像。它在数据流中查找重复块,将它们保存在字典中并重新引用它们。如果 100 个像素在某处重复,则只使用一个代码来重现这 100 个像素,而不是像位图 (BMP) 图像那样使用 100 个。这就是为什么 GIF 非常适合图表,其中您可能有许多 100 个白色像素系列,然后是一些黑色像素来绘制一条线。另一方面,它对于照片来说很糟糕,因为很少有长时间的重复,而且除非你使用一些复杂的技巧,否则 GIF 通常被限制为 256 色。

    压缩文件中使用的代码比原始图像中每个像素的颜色代码长。只是因为长重复块在图表中很常见,才可能进行大规模压缩。

    【讨论】:

      猜你喜欢
      • 2016-04-11
      • 2014-10-10
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 2019-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多