sprite-slicer
sprite-slicer 是一个面向 2D 游戏素材流程的 Rust crate,既能作为命令行工具使用,也能作为库嵌入到你自己的工具链中。
它解决的是一条完整的 sprite 处理链路:
- 把规则 sprite sheet 按网格切成单帧
- 从透明背景图中自动检测单帧
- 按动作把帧重新分组
- 去除黑色背景并转透明 PNG
- 把一组帧统一到同一画布和锚点
- 导出 GIF 预览动画
仓库地址:
- GitHub: https://github.com/mdddj/sprite-slicer
- docs.rs: https://docs.rs/sprite-slicer
适用场景
- AI 生成了一整张角色动作图,需要切成单帧
- 一张图里角色站位不规则,需要自动检测角色块
- 想把帧按
idle / walk / attack / hurt分到不同目录 - 想把黑底或近黑底图片转成透明背景 PNG
- 想把动作帧对齐到统一尺寸,避免游戏里角色抖动
- 想快速导出 GIF 看动画节奏是否正常
特性
- 同时提供
CLI和library API - 输入输出都是文件和目录,适合脚本、工具链、AI agent 调用
- 支持规则网格切图和透明图自动检测
- 支持动作分组导出
- 支持背景去除和帧规范化
- 支持 GIF 预览导出
- 适合像素角色、敌人动画、JRPG sprite workflow
安装
作为库:
作为命令行工具:
目录约定
这个库是“文件导向”的。大多数 API 都会:
- 从一个图片文件或目录读入
- 在输出目录里生成 PNG、TOML、TXT、GIF
- 返回一个包含产物路径和统计信息的结果结构体
默认产物通常包括:
frames/:切出来的 PNG 单帧frames.toml:帧清单 manifestindex-map.txt:便于肉眼核对帧序号的文本图actions.toml:动作分组后的摘要清单
给 AI 调用的建议
如果你后续要让别的 AI 直接操作这个库,建议固定用下面这套顺序:
- 如果原图是黑底或纯色底,先调用
remove_background - 如果是规则网格图,调用
slice_sheet - 如果不是规则网格、已经是透明底,调用
detect_frames - 根据
frames.toml生成动作配置,再调用group_actions - 对每个动作目录调用
normalize_frames - 对每个动作目录调用
export_gif做预览
建议 AI 遵循这些约束:
- 所有输入路径都使用绝对路径
- 输出目录不要复用未清理的旧结果目录
group_actions之前必须确保frames.toml已生成normalize_frames和export_gif只接受 PNG 文件或只包含 PNG 的目录- 对 AI 生成图优先尝试
detect_frames,对规则表格图优先尝试slice_sheet
AI 调用模板
下面这段可以直接复制给别的 AI,当作它操作这个库的规则。
你正在操作一个 Rust 库:sprite-slicer。
目标:
- 处理 2D sprite sheet
- 产出单帧 PNG、动作目录、规范化帧和 GIF 预览
公开函数:
- slice_sheet(SliceOptions) -> Result<SliceOutput>
- detect_frames(DetectOptions) -> Result<DetectOutput>
- group_actions(GroupOptions) -> Result<GroupOutputSummary>
- normalize_frames(NormalizeOptions) -> Result<NormalizeOutput>
- export_gif(GifOptions) -> Result<GifOutput>
- remove_background(RemoveBgOptions) -> Result<RemoveBgOutput>
工作流规则:
1. 如果输入图是黑底或纯色背景,先调用 remove_background。
2. 如果图像是规则网格,调用 slice_sheet。
3. 如果图像不是规则网格但背景透明,调用 detect_frames。
4. 必须根据 frames.toml 中的 frame index 来生成 group_actions 的配置。
5. 动作分组完成后,对每个动作目录调用 normalize_frames。
6. 预览动画时,对规范化后的动作目录调用 export_gif。
路径规则:
- 输入输出路径尽量使用绝对路径。
- 不要把不同步骤的结果写到同一个未清理目录。
- normalize_frames 和 export_gif 的输入必须是 PNG 文件或仅包含 PNG 的目录。
- 目录输入时,这个库只扫描当前目录下一层 PNG,不做递归扫描。
参数选择建议:
- 黑底去背:bg_hex = "#000000",threshold 从 8 开始尝试。
- AI 生成图自动检测:min_opaque_pixels 从 64 开始,padding 从 2 开始,row_tolerance 从 24 开始。
- 角色动画对齐:anchor_x = Center,anchor_y = Bottom,pad = 2 或 4。
- GIF 预览:fps = 8 或 12,repeat = 0。
错误处理建议:
- 如果 detect_frames 报 no components matched,降低 min_opaque_pixels,或调整 alpha/background threshold。
- 如果 group_actions 报 frame index 不存在,检查动作配置里的索引是否来自 frames.toml。
- 如果 group_actions 报 frame was not exported,说明切图时 skip_empty 把该帧跳过了。
- 如果 export_gif 或 normalize_frames 报 no png frames found,检查输入目录是否真的有 PNG。
公开 API 总览
当前公开函数一共 6 个:
slice_sheet(options: SliceOptions) -> Result<SliceOutput>detect_frames(options: DetectOptions) -> Result<DetectOutput>group_actions(options: GroupOptions) -> Result<GroupOutputSummary>export_gif(options: GifOptions) -> Result<GifOutput>remove_background(options: RemoveBgOptions) -> Result<RemoveBgOutput>normalize_frames(options: NormalizeOptions) -> Result<NormalizeOutput>process_sprite_sheet(options: ProcessSheetOptions) -> Result<ProcessSheetOutput>
可直接引入:
use ;
快速示例
1. 黑底转透明
use PathBuf;
use ;
2. 规则网格切图
use PathBuf;
use ;
3. 透明图自动检测
use PathBuf;
use ;
4. 按动作分组
use PathBuf;
use ;
5. 统一帧尺寸和锚点
6. 洋红底 sprite sheet 后处理
这个入口更接近 AI 生成 sprite 的实际落地流程:去洋红背景、切网格、按最大主体或整帧裁剪、统一缩放、重新拼 sheet、导出 GIF,并输出 pipeline-meta.json。
use PathBuf;
use ;
use PathBuf;
use ;
6. 导出 GIF 预览
use PathBuf;
use ;
API 详细说明
slice_sheet
签名:
用途:
- 适合规则网格的 sprite sheet
- 按固定宽高、固定行列切出单帧
- 可跳过空白格
SliceOptions 字段说明:
input: 输入图片路径output: 输出目录frame_width: 单帧宽度frame_height: 单帧高度columns: 列数;None时自动推导rows: 行数;None时自动推导offset_x: 左侧起始偏移offset_y: 顶部起始偏移gap_x: 横向间距gap_y: 纵向间距skip_empty: 是否跳过空白帧导出alpha_threshold: alpha 小于等于该值时当作透明min_opaque_pixels: 前景像素少于该值时视为空帧bg_hex: 可选背景色,形如#000000bg_threshold: 背景颜色容差manifest_name: 输出 manifest 文件名,通常是frames.toml
输出 SliceOutput:
manifest_path: manifest 路径index_map_path: 文本索引图路径frame_count: 总格子数kept_frames: 实际导出的帧数
会生成:
output/frames/*.pngoutput/<manifest_name>output/index-map.txt
适合 AI 的判断规则:
- 如果图片是标准行列排布,用它
- 如果帧之间不规则、大小不一致,不要用它
detect_frames
签名:
用途:
- 适合透明背景图
- 用连通区域检测方式识别每个 sprite
- 自动按行聚类并编号
DetectOptions 字段说明:
input: 输入图片路径output: 输出目录alpha_threshold: alpha 小于等于该值时视为空气min_opaque_pixels: 小于该前景像素数的连通块会被忽略padding: 对检测框四周补边row_tolerance: 自动分行时允许的垂直容差bg_hex: 可选背景色;即使不是透明图,也可配合颜色过滤bg_threshold: 背景颜色容差manifest_name: 输出 manifest 文件名
输出 DetectOutput:
manifest_path: manifest 路径index_map_path: 文本索引图路径detected_frames: 检测到的帧数rows: 聚类出的行数
会生成:
output/frames/*.pngoutput/<manifest_name>output/index-map.txt
适合 AI 的判断规则:
- AI 生成图优先尝试这个函数
- 如果报
no components matched,通常要降低min_opaque_pixels或调整阈值
group_actions
签名:
用途:
- 根据动作配置,把切好的帧复制到各自动作目录
- 适合把一堆
frames/*.png重新组织成idle/ walk/ attack/
GroupOptions 字段说明:
manifest:slice_sheet或detect_frames产出的frames.tomlconfig: 动作配置 TOML 文件output: 动作输出目录
动作配置格式:
[[]]
= "idle"
= [0, 1, 2, 3]
[[]]
= "walk"
= [4, 5, 6, 7]
输出 GroupOutputSummary:
manifest_path: 输出的actions.tomlactions: 每个动作的摘要列表
每个摘要项 GroupedActionSummary 包含:
name: 动作名frame_count: 帧数量
会生成:
output/<action-name>/0000.pngoutput/<action-name>/0001.pngoutput/actions.toml
注意:
frames里填的是frames.toml里的帧索引,不是文件名- 如果某帧在切图阶段因为
skip_empty没导出,这里会报错
normalize_frames
签名:
用途:
- 把一组 PNG 帧放到同样大小的画布上
- 用统一锚点对齐,减少游戏里跳动感
NormalizeOptions 字段说明:
input: 输入 PNG 文件或目录output: 输出目录width: 目标宽度;None时使用输入帧中的最大宽度height: 目标高度;None时使用输入帧中的最大高度anchor_x: 水平锚点,支持Left / Center / Rightanchor_y: 垂直锚点,支持Top / Center / Bottompad: 每边额外留白
输出 NormalizeOutput:
output_dir: 输出目录frame_count: 输出帧数canvas_width: 最终画布宽度canvas_height: 最终画布高度anchor_x: 实际使用的水平锚点anchor_y: 实际使用的垂直锚点
输入规则:
- 传文件时,必须是 PNG
- 传目录时,只会扫描该目录下一层的 PNG,不会递归
适合游戏导入的默认建议:
- 角色动画推荐
AnchorX::Center + AnchorY::Bottom - 顶视角特效可考虑
Center + Center
export_gif
签名:
用途:
- 从单个 PNG 或一个 PNG 目录生成 GIF 预览
- 方便先肉眼检查动作节奏
GifOptions 字段说明:
input: 输入 PNG 文件或目录output: 输出 GIF 路径fps: 帧率,最小按 1 处理repeat: 重复次数,0表示无限循环pad: 给 GIF 画布四周加留白
输出 GifOutput:
output_path: GIF 路径frame_count: 帧数canvas_width: GIF 画布宽度canvas_height: GIF 画布高度fps: 实际使用的帧率
输入规则:
- 传目录时,只读取该目录下一层的 PNG
- 文件名会先排序,再按顺序组成 GIF
建议:
- 最好先用
normalize_frames,再导出 GIF - 这样每帧尺寸一致,预览更稳定
remove_background
签名:
用途:
- 把和边界连通的背景色抠掉,转成透明
- 适合黑底、纯色底、近纯色底 sprite 图
RemoveBgOptions 字段说明:
input: 输入图片路径output: 输出 PNG 路径bg_hex: 背景颜色,例如#000000threshold: 颜色容差alpha_threshold: 已经接近透明的像素阈值
输出 RemoveBgOutput:
output_path: 输出路径removed_pixels: 被清成透明的像素数
这个函数的行为不是“删除所有黑色像素”,而是:
- 从图片边界开始找背景
- 只删除和边界连通的背景区域
这样更安全,能尽量保住角色内部描边、眼睛、武器暗部这些黑色细节。
公开类型
对外暴露的主要类型有:
SliceOptionsDetectOptionsGroupOptionsGifOptionsRemoveBgOptionsNormalizeOptionsSliceOutputDetectOutputGroupedActionSummaryGroupOutputSummaryGifOutputRemoveBgOutputNormalizeOutputSliceManifestFrameRecordDetectionModeActionSpecAnchorXAnchorY
AnchorX
支持:
AnchorX::LeftAnchorX::CenterAnchorX::Right
字符串解析也支持:
"left""center""right"
AnchorY
支持:
AnchorY::TopAnchorY::CenterAnchorY::Bottom
字符串解析也支持:
"top""center""bottom"
Manifest 格式
slice_sheet 和 detect_frames 生成的 manifest 都是 SliceManifest。
关键字段:
source: 原图路径frame_widthframe_heightcolumnsrowsoffset_xoffset_ygap_xgap_yalpha_thresholdmin_opaque_pixelsbg_hexbg_thresholddetection:grid或connected_componentsframes: 帧列表
frames 中每项是 FrameRecord:
index: 帧索引row: 所在行column: 所在列x: 原图裁剪起点 xy: 原图裁剪起点 ywidthheightopaque_pixelskept: 是否保留导出file: 导出的相对文件路径,可为空
示例:
= "/abs/path/sheet.png"
= 64
= 64
= 4
= 2
= 0
= 0
= 0
= 0
= 0
= 1
= 0
= "grid"
[[]]
= 0
= 0
= 0
= 0
= 0
= 64
= 64
= 3210
= true
= "frames/frame_0000_r00_c00.png"
CLI 用法
按网格切图
从透明图自动检测单帧
按动作分组
导出 GIF 预览
去除黑色背景
统一帧尺寸和锚点
推荐工作流
工作流 1:AI 生成黑底整图
remove_backgrounddetect_framesgroup_actionsnormalize_framesexport_gif
工作流 2:规则像素角色表
slice_sheetgroup_actionsnormalize_framesexport_gif
工作流 3:导入游戏前整理
- 对每个动作目录调用
normalize_frames - 把归一化后的 PNG 导入游戏引擎
- 预览时用
export_gif做检查
游戏导入建议
这个库本身不绑定具体引擎,但整理后的结果适合导入:
- Flutter Flame 2D
- Godot
- Cocos Creator
- Unity 2D
- 自己写的 sprite animation 系统
常见做法:
- 一个动作一个目录,如
idle/、walk/、attack/ - 每帧文件名按
0000.png、0001.png递增 - 游戏里按目录读取并排序
- 锚点统一后,角色切动作时位置更稳定
依赖
imagegifserdetomlclapanyhow
发布状态
当前 crate 已经是 lib + bin 结构,并且已通过:
发布到 crates.io: