跳到主要内容
AZ Tools

GIF 结构检查器

本工具像解码器那样逐块遍历 GIF,从 13 字节的文件头一直走到 0x3B 结尾标记,中间不靠猜测跳过任何字节。文件头给出版本(GIF87a 完全没有扩展块,能做动画的是 GIF89a)、各帧合成所用的逻辑屏幕、背景色索引、三十年来没有任何浏览器理会的像素宽高比字节,以及是否存在全局调色板、有多少项、占几位。随后列出每一帧,并附上决定播放效果的两个值:延迟和处置方式。GIF 显得慢,原因通常就是延迟:它以百分之一秒为单位存储,而浏览器会把大约 20 毫秒以下的值悄悄换成 100 毫秒,于是按每帧 5 毫秒制作的文件比作者设想的慢了五倍。因此这里同时给出两个总时长:延迟相加的结果,以及你实际会看到的长度。处置方式则解释拖影和闪烁:恢复为背景会在下一帧之前清掉本帧矩形,恢复到上一帧会把画布回退,而保留不动正是让优化器只存储变化像素的前提。这种优化在这里同样看得见:小于逻辑屏幕的帧会被标出,并显示它的位置、是否自带局部调色板、是否隔行、以及透明索引。由于子块链是被精确跟随而不是靠扫描找到的,每帧的字节开销是准确值,表格还会按开销排序,让把文件撑到 20 MB 的那一帧排在最上面。剩余字节被拆分为调色板、LZW 图像数据和分块开销,每个扩展块(图形控制、注释、纯文本、应用程序,包括 NETSCAPE 循环计数器和无法识别的块)都会连同偏移、大小和文本一起列出。它不做的事情是解码像素:LZW 数据只被测量,从不解压,所以关于色彩还原、抖动或帧间相似度它给不出任何结论。被截断的文件,或者块长度越过文件末尾的文件,会以带名字的错误被拒绝,而不是读一半就算数——因为从那个位置往后,任何偏移都只是猜测。

使用方法

  1. 把 .gif 拖到方框里,或点击选择文件。字节在页面内读取,不会上传。
  2. 先看概览:文件头版本、逻辑屏幕、帧数、浏览器实际播放的时长以及循环方式。
  3. 如果出现播放警告,说明帧延迟低于浏览器下限。把延迟提高到 20 毫秒以上,否则文件永远比标称的慢。
  4. 体积问题去看帧表:字节列和进度条显示哪些帧最贵,尺寸旁带 * 表示该帧只重绘画布的一部分。
  5. 在扩展块列表里检查 NETSCAPE 循环块、编码器留下的注释,以及任何你没预料到的应用程序块。

常见问题

为什么我的 GIF 播放得比设定的延迟还慢?
因为浏览器拒绝极短的延迟。延迟存放在每帧的图形控制扩展里,单位是百分之一秒,所以非零的最小值是 10 毫秒;但 Blink 和 WebKit 会把低于 11 毫秒的值换成 100 毫秒,Gecko 则是低于 20 毫秒时这么做。于是按“50 fps”导出的文件实际只有 10 fps,慢了十倍,而且没有任何标志能绕过它:这个限制源自当年满页都是用作占位的一帧 GIF,如今所有引擎仍在执行。本工具同时给出延迟之和与浏览器实际耗时,让你分清是被下限拉长的文件还是本来就长的文件。如果确实需要快速动画,答案是视频编码而不是 GIF。
循环次数到底表示什么?
循环根本不在 GIF 规范里。它是网景公司 1995 年加入的应用程序扩展:11 字节标识 NETSCAPE2.0,后面跟一个含 16 位计数的子块。0 表示无限循环,几乎所有编码器都写这个值。非零值是首次播放之后额外播放的次数,所以 1 在 Chrome 和 Firefox 中会播两遍,不过少数老式阅读器把它当作总次数。如果这个块完全缺失,动画只播一次就停在最后一帧——文件经过会丢弃未知扩展的工具处理后,常常出现这种意外。
为什么我的 GIF 这么大?
几乎总是因为每一帧都保存整个画面,而不是只保存变化的部分。这里的字节列把一帧的全部开销都算在它头上:图形控制扩展、图像描述符、局部调色板和 LZW 数据,所以排名是精确值而非估算。主导因素有三个:整帧重写,即每帧都和逻辑屏幕一样大;局部调色板,256 项就是 768 字节,六十帧在放入一个像素之前已经是 45 KB;以及 LZW 本身,它对照片和抖动图像表现很差,压完可能比原始索引还大。字节明细会把这三项分开列出。
什么是处置方式?为什么画面会留下残影?
GIF 的每一帧都画在前一帧留下的画布上,处置方式规定在绘制下一帧之前如何处理当前帧。0(未指定)和 1(不处置)会保留画面,这正是差分帧成立的前提——只需存储变化的像素。2 会把该帧矩形清回背景,当透明像素不能层层堆叠时就需要它,但每次都清空整屏就会看到闪烁。3 恢复到该帧绘制前的画面,代价高且各实现并不一致。拖尾和残影几乎总是因为该用 2 的地方用了 1,或者把透明像素叠在从未清除过的画面上。
为什么透明边缘看起来是锯齿?
GIF 的透明是一个调色板索引,而不是 alpha 通道。一帧可以指定某一项为透明,合成时带该索引的像素会被跳过;在完全不透明和完全透明之间没有中间地带。因此 PNG 那种抗锯齿边缘无处安放:半透明像素要么与导出工具假定的背景混合,留下常见的白边或灰边,要么被压成透明索引,于是出现阶梯。它还要占掉一种颜色:带透明的图像可用的是 255 项而不是 256 项。另外透明索引是逐帧的,解码器只会报告当前帧的那一个。
GIF87a 和 GIF89a 有什么区别?隔行还有用吗?
GIF87a 是 1987 年的原始格式,完全没有扩展块,也就意味着没有延迟、没有透明、没有循环计数、没有注释。GIF89a 增加了扩展机制,人们心目中 GIF 的种种特性都在其中。两者今天都能被普遍读取,当不需要 89a 专有功能时,编码器写成 87a 是合理的——单张静态图通常就是这种情况。隔行是另一个逐帧的标志:行数据分四遍存储,让只下载了一部分的图像先显示出整幅画面的粗略版本。在现代网络上它没有好处,而且打断了相邻行之间的相关性,反而让 LZW 数据略微变大,所以出现隔行帧多半说明文件经过了某个老工具。

相关工具