GIF 提取帧
把动图拆成一帧一张图片:先看清总帧数、每帧延时和循环次数,再逐帧导出 PNG,或者按帧号挑着导、打包全部导出、拼成一张精灵图。
也可以把 .gif 文件直接拖到这个面板里。解析只在浏览器本机完成,动图不会上传;支持 WebCodecs 的浏览器会走内核解码,其余浏览器用自带解析器逐块还原。
GIF 是怎么叠出来的
GIF 不是一串独立图片,而是一段指令流:每一帧只描述自己覆盖到的那一小块矩形(可以带偏移,比整屏小),怎么和上一帧叠、显示完要不要擦掉,写在帧前面的 Graphic Control Extension 里,也就是常说的 disposal 处置方式。留着(0 和 1)表示下一帧继续叠在这一帧上面;清成透明(2)表示这一帧显示完就把它占的矩形擦掉,露出下层;还原上一帧(3)表示这一帧显示完要回到画它之前的样子。只按顺序把每帧铺上去,遇到 2 和 3 就会留下残影,这就是「拆帧拆出一堆鬼影」的来源。
帧里那些颜色索引还要过一遍 LZW 解压才能变成像素。压缩时用变长编码:从「最小码长加一」位起,字典每填满 2 的幂个条目就加一位,读到 Clear Code 要整体复位。字典本身用「前缀码 + 末字节」两个平行数组表示,因为一张 500 × 500 的图会产出 25 万个索引,存成字符串会把内存放大几十倍。解出来的索引还要按调色板查成 RGB,其中等于透明索引的那些像素要跳过,语义是「这一像素不动,露出下层」,而不是画一个透明点。
另一个容易漏掉的是隔行扫描(interlace)。开启之后像素按四遍存放:先隔 8 行取一遍,再错开 4 行,再错开 2 行,最后补齐剩下的行。解出来必须按这个顺序重排回逐行存储,否则得到的是一张横条纹的图。这一页只在帧的 Image Descriptor 里标了 interlace 时才做重排,普通 GIF 走原路,不做多余计算。
延时字段的单位是 1/100 秒,值 0 的本意是「尽快显示下一帧」,但各家浏览器早就把它统一成 100 毫秒了,所以界面上既如实显示字段值,也按 100 毫秒计入总时长。整屏尺寸也有硬上限:每一帧都要留一份完整 RGBA 快照,所以一次最多拆 300 帧、整屏不超过 24 兆像素,超了就明确提示被截断,不会假装成功。想拿的是视频里的单张画面,用视频截图取帧;想把帧重新拼成动图,用视频转 GIF。
常见问题
为什么有的帧拆出来带着上一帧的残影?
这是 GIF 的叠加规则在起作用。动图的每一帧往往只描述自己覆盖的那一小块矩形,叠不叠在上一帧上、显示完要不要擦掉,由帧前面的处置方式决定:留着(0 和 1)、显示完把这块清成透明(2)、显示完还原成画它之前的样子(3)。这一页按这三种规则逐帧合成,所以拿到的每一帧都是当时屏幕上真实的样子;如果你用别的工具拆出残影,多半是它忽略了 2 和 3。
帧延时显示 0 是什么意思?
延时字段的单位是 1/100 秒,写 0 的本意是「尽快显示下一帧」,但浏览器早就统一把它当成 100 毫秒,也就是 10 帧每秒。这一页在界面上会如实标出文件里写的是 0,算总时长时按 100 毫秒计,因为那才是你实际看到的播放速度。
总时长和播放器上显示的不一样?
总时长是把每帧延时累加出来的,不包含浏览器渲染和加载的时间,所以会比实际播放略短一点点。另外有些 GIF 的延时字段写得很随意(比如全是 10 毫秒),播放器会照做,观感上就是飞快;这里显示的就是那份延时,不会替你去改。
为什么最多只拆 300 帧?
因为每一帧都要留一份完整的 RGBA 快照。一张 500 × 500 的图单帧就是 1 兆字节,1000 帧就是 1 个 GB,标签页会直接被浏览器回收。所以拆到 300 帧就停下并明确提示被截断了,不会假装成功。要处理更长的动图,先用桌面工具剪短,或者调小尺寸另存一份。
有些浏览器说是 WebCodecs 解码,有什么区别?
Chrome、Edge 支持 WebCodecs 的 ImageDecoder,交给它按帧解码最稳,叠加和擦除都由内核负责,延时的精度也更好。Safari、Firefox 没有这个接口,就会回退到这一页自带的解析器:自己读文件头、色表、控制块,做 LZW 解压和叠加合成。两条路解出来的帧内容一致,只是把哪条路用的原始数值读了出来,所以在结果里标了来源。
导出的帧是全尺寸的还是缩略图?
全尺寸,和 GIF 整屏一样大,导出的是无损 PNG。列表里那些小图只是为了排得下而缩过的预览,点「导出这一帧」会按原尺寸重新生成一遍,所以不会拿到糊的小图。要注意 GIF 只有 256 色,PNG 无损也救不回本来就少的颜色,导出的图会保留 GIF 的色带。
精灵图的列数该怎么定?
帧数少(16 帧以内)用横排最省事,前列顺序就是帧顺序,写 CSS 的时候按序号累加宽度即可。帧数多就摊成方阵,让整图的长宽比接近 1:1,这样纹理贴图在 GPU 上更好处理,也避免出现一张长到 8000 像素的横条——部分设备对单张纹理的边长有 4096 或 8192 像素的上限。