ZeroTool Workbench
GIF 拆帧工具
在线 GIF 拆帧:把动图逐帧导出为 PNG 或 JPG,批量打包 ZIP,或拼接雪碧图并生成帧坐标 JSON。按 disposal 正确合成完整帧,浏览器本地处理不上传。
使用步骤
- 把 GIF 拖进上传区,或点击选择文件,也可以用 Ctrl/Cmd+V 粘贴已复制的 GIF 文件。
- 看一眼信息栏:画布尺寸、帧数、总时长、首遍后重复次数和文件大小。
- 选帧。默认全部选中:点缩略图单独切换;用「全选 / 全不选」批量操作;或填写「第 1 到 48 帧,每隔 4」后点「按此选择」,按范围或间隔挑帧。
- 选择 PNG(保留透明)或 JPG(可调质量,并为透明区域指定背景色)。
- 点「下载 ZIP」打包全部已选帧,或点缩略图下方的下载图标单独保存一帧。文件名形如
{原名}-frame-001.png。 - 需要雪碧图时,设置列数和间距,点「生成雪碧图」,再下载 PNG 与 JSON,或直接复制 JSON。
为什么导出的帧是完整画面
GIF 并不是一叠完整图片。从第二帧起,编码器通常只写入发生变化的矩形区域,没变的像素标成透明。每帧还带一个处置方式(disposal):
| disposal | 含义 | 下一帧从什么状态开始 |
|---|---|---|
| 0 / 1 | 保留 | 本帧留在画布上 |
| 2 | 恢复为背景 | 本帧所在矩形清成透明 |
| 3 | 恢复为上一状态 | 画布回到绘制本帧之前的样子 |
直接导出这些碎片,得到的是一块块带洞的残图。本工具维护一张持续累积的画布,按顺序执行每帧的处置规则,并在每帧画完后复制一份画布作为输出。所以每张 PNG 都是那一刻的完整画面,尺寸统一为画布大小,第 12 帧和第 1 帧可以逐像素对齐。
雪碧图与 JSON 坐标
雪碧图把已选帧按从左到右、从上到下的顺序排成网格,格子之间可以留间距,间距部分保持透明。配套 JSON 示例:
{
"image": "loader-sprite.png",
"width": 256,
"height": 64,
"frameWidth": 64,
"frameHeight": 64,
"columns": 4,
"spacing": 0,
"frames": [
{ "frame": 1, "x": 0, "y": 0, "w": 64, "h": 64, "duration": 80 },
{ "frame": 2, "x": 64, "y": 0, "w": 64, "h": 64, "duration": 80 }
]
}
frame 记录的是原始帧号,跳过了哪些帧一眼可见;duration 单位为毫秒。
想用纯 CSS 播放,把「列数」设成已选帧数,得到单行雪碧图,再用 steps() 逐格切换:
.loader {
width: 64px;
height: 64px;
background: url(loader-sprite.png) 0 0 / auto 64px;
animation: play 0.32s steps(4) infinite;
}
@keyframes play {
to { background-position: -256px 0; }
}
常见用途
- 从表情包或录屏 GIF 里截一张清晰静帧,无损 PNG 直接放进 PPT、Bug 报告或封面。
- 把 GIF 转成游戏雪碧图,交给 Phaser、PixiJS、Cocos、Godot 或手写 Canvas 循环,帧时长保存在 JSON 里。
- 用 CSS
steps()动画替换体积大的 GIF,或只挑几帧另存为 WebP。 - 逐帧检查 UI 动效,定位布局跳动或过渡闪烁出现在哪一帧。
- 每隔 N 帧抽一张,给长 GIF 做分镜或缩略总览。
用 ffmpeg 不行吗?
超大文件就该用 ffmpeg,它同样会正确合成帧。但有个坑:默认参数会把延迟不一的 GIF 重采样成固定帧率,5 帧的 GIF 可能导出几十张重复 PNG。加上 -fps_mode passthrough 才能一帧一张:
ffmpeg -i input.gif -fps_mode passthrough frame-%03d.png
本页免安装就能得到同样的帧,还能可视化挑帧,一步生成雪碧图和 JSON。
实现原理
本页自己解码 GIF,没有用浏览器内置的图片解码接口,因为 WebCodecs 的 ImageDecoder 并非所有浏览器都支持,也拿不到每帧的处置方式。解码器依次读取逻辑屏幕描述符、全局与局部颜色表、图形控制扩展(延迟、处置方式、透明色)和 NETSCAPE2.0 循环次数,再解压每帧的 LZW 数据:码宽从最小码长逐步增长到 12 位,遇到 clear code 重置字典。隔行扫描的帧按四趟行序还原。文件中途截断时,断点之前已解出的像素照常保留。解码分小段执行,大文件也不会卡住页面,并显示进度。
范围说明
- 帧始终按完整画布尺寸导出,裁剪和缩放不在本工具范围内;需要缩放可以把导出的帧交给图片压缩工具。
- 输出格式为 PNG、JPG、二者的 ZIP 包,以及 PNG 雪碧图。要转 WebP 请用 WebP 转换器。
- 编辑或重新合成 GIF 动图不在范围内,本工具只负责拆。
- 尺寸上限:解码后 5000 万像素、1000 帧,单帧或雪碧图 16,777,216 像素。
相关工具
FAQ
导出的是完整画面,还是只有变化部分的碎片?
是完整画面。大多数 GIF 每帧只存一块变化区域,再用 disposal(处置方式)规定下一帧开始前怎么处理它。本工具按 0/1/2/3 四种处置方式逐帧合成,导出的每一帧都和浏览器播放时看到的一致。按设计不提供原始碎片帧;确实需要时,请在本地用 gifsicle --explode。
GIF 会被上传到服务器吗?
不会。文件通过 File API 读取,由本页 JavaScript 在浏览器里解码;PNG/JPG 编码、ZIP 打包、雪碧图拼接也都在本地完成。本地只保存导出偏好(格式、JPG 质量、背景色、列数、间距),GIF 文件和帧数据从不写入任何存储。
能处理多大的 GIF?
上限是解码后 5000 万像素(宽 × 高 × 帧数)、1000 帧,单帧和雪碧图不超过 16,777,216 像素(单边 16,384 px)。帧以未压缩形式保存在内存中,这个上限保证手机也能跑完。480×270、385 帧的 GIF 仍在范围内。更大的文件请在本地运行 ffmpeg -i input.gif -fps_mode passthrough frame-%03d.png。
文件里写的延迟是 0,为什么显示 100 ms?
主流浏览器会把 10 ms 及以下的帧延迟(GIF 以百分之一秒为单位,即 0 或 1)按 100 ms 播放。本工具显示和导出的是实际播放时长,雪碧图 JSON 因此与浏览器里的效果一致。20 ms 及以上的延迟保持原值。
雪碧图 JSON 里有哪些字段?
图片文件名、雪碧图宽高、单帧宽高、列数、间距,以及每帧一条记录:原始帧号 frame、坐标 x / y、尺寸 w / h、时长 duration(毫秒)。可以直接交给游戏引擎、Canvas 动画循环或 CSS 关键帧使用。