为啥块之间的 GIF 编码/解码中有这么多填充

Posted

技术标签:

【中文标题】为啥块之间的 GIF 编码/解码中有这么多填充【英文标题】:Why is there so much padding in GIF Encoding/Decoding between blocks为什么块之间的 GIF 编码/解码中有这么多填充 【发布时间】:2019-05-27 05:22:42 【问题描述】:

我一直在为我正在处理的项目开发一个自定义 GIF 解码器,该项目需要尽可能少的 GIF 数据存储在 RAM 中(因此我可以根据需要有效地从文件中提取所有内容它,一个字节一个字节)。

我一直在学习以下教程:

http://matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp

在规范本身的帮助下:

https://www.w3.org/Graphics/GIF/spec-gif89a.txt

我可以使用我的解码器制作非动画 GIF 和交通灯动画示例。但是,当我尝试浏览从 www.piskelapp.com 导出的 GIF(它使用 gif.js 作为其导出器)时,我会在不同的块之间得到很多填充,在某些情况下根据规范。

例如,以下动画https://www.piskelapp.com/p/agxzfnBpc2tlbC1hcHByEwsSBlBpc2tlbBiAgICA_eOjCgw/edit 的开头如下所示:

47 49 46 38 39 61 20 00 20 00 F7 00 00 00 00 00 4E 4E 4E FF FF 00 00 00 00 00

前 6 个字节应该是标题(ASCII 格式的 GIF89a),接下来的 7 个字节应该是逻辑屏幕描述符 (LSD)。鉴于这里的信息,紧随其后的是一系列与 LSD 中颜色数量相匹配的颜色数据。但事实并非如此,它只是 3 个“00”、3 个“4E”和 2 个“FF”,然后是一个持续 760 个字节的 00 字符串。在 760 之后,我来到了图形控制扩展(这是预期的,用 0x21 表示)。这发生在以下许多块之间,除了我没有看到任何我期望的扩展代码,也没有在正确的位置看到图像描述符(应该以 2C 开头)。

总而言之,我是否遗漏了规范中的某些内容?这一切是什么,看起来像什么,填充以及如何规避它?我在使用其他编码器的其他 GIF 文件中看到了其他类型的这种填充,并且似乎没有一致的代码可供我寻找。该文件在 Windows 照片中有效,所以一定有我遗漏的东西。

【问题讨论】:

能否将目标 GIF 文件提供为文件?我没有在 Piskel 注册,所以我只能得到一个 .piskel 文件,它实际上是带有一些随附元数据的 base64 编码的 PNG,但不是 GIF。 【参考方案1】:

答案相当简单。 Piskel 使用的 GIF 导出器的实现很差。

它在 GIF89a 规范中明确说明:

"应考虑此处指定的图形交换格式(sm) 完全的;任何偏离它的行为都应被视为无效,包括但不 仅限于使用控制或数据中的保留或未定义字段 块,在块内或块之间包含无关数据,使用 方法或算法未明确列为格式的一部分等。”

我想指出的是“在块内或块之间包含无关数据”。在这种情况下,问题是块内的数据,出于某种原因,Piskel 使用的导出器总是用黑色填充所有剩余空间的颜色表(全局和本地)。在发现可能的解码实现是错误的之后,我意识到了这一点,这在点击重复的“黑色”(#000000)颜色代码时会导致问题。

更多信息可以在规范本身中找到,位于此处:

https://www.w3.org/Graphics/GIF/spec-gif89a.txt

【讨论】:

以上是关于为啥块之间的 GIF 编码/解码中有这么多填充的主要内容,如果未能解决你的问题,请参考以下文章

如果输入长度不能被 3 整除,为啥 base64 编码需要填充?

为啥在编码“填充掩码”时添加了新的暗淡

为啥这种红色只填充一帧 PIL?

使用 Codable 解码 JSON,然后填充我的 SwiftUI

为啥当我使用 .map 而不是硬编码来动态填充内容时,Material UI 选项卡停止工作?

iOS上的Base64编码最后缺少填充