表情包工坊
这是什么
输入 一张人物参考图(可选加一个风格词),输出:
- 一张带透明通道的 3×3 九宫格母版
- 9 张切好的独立透明 PNG(可直接导入微信静态表情)
- 9 条循环透明 GIF(默认本地生成,画布 240×240,微信友好)
- 按平台规格整理好的目录 + ZIP + 总览预览图 + 导入说明
- 一份质检报告:格子数、透明通道真实性、格缝是否干净、体积是否超限
可选延伸:把 9 条 GIF 按固定文件名整理,做成 ChatGPT 桌面端的自定义 Pet。
核心原则
- 最小输入 = 一张参考图。 用户给了图就直接跑,不要反问风格、数量、平台。
风格没说 → 默认「大头小身体的夸张 Meme 风」(
style-registry.md的chibi-pop方向)。 平台没说 → 默认wechat档位。 - 透明和身份一致性优先级高于画风。 任何时候都不为了追求风格牺牲 "背景真透明、人物完整、九格互不粘连"。
- 先本地、再模型。 切图、抠像、动效、打包全部本地完成,可复现、不花额度。 只有"母版生成"和"可选的视频动效"需要调生成模型。
- 不做二次叠加。 用户要求改风格时,沿用同一张原图重出母版, 不要在已经风格化的图上再转一次(会累积失真、丢身份)。
输入解析
按顺序找参考图,找到即用:
- 本轮用户消息里附带的图片路径(
<attached_files>/ 拖入路径) - 用户直接写的绝对路径
- 本会话中用户最近一次提供的图片路径
- 都没有 → 才问一句图在哪
情绪 / 动作清单:用户可以给 9 个(写入 --labels),
也可以只给一个主题,由你补全整套。补全时按"情绪光谱"铺开,
避免九张都是同一种情绪。可用的默认九宫格:
无语, 哭, 震惊, 得意, 白眼, 问号, 比心, 冲, 笑
按人设改写更好用,例如连载作者:
催更, 收到, 真的假的, 我裂开了, 牛啊, 学废了, 别急, 马上来, 离谱
执行流程
阶段 0:环境准备(每个会话第一次跑)
技能自带零依赖的引导脚本,会自动建本地 venv 并装好 Pillow(+ 可选 numpy):
python scripts/setup_env.py # 建 .venv 并装依赖;结尾会打印解释器路径
引导完成后,下文所有 <PY> 都指这个 venv 解释器:
- Windows:
.venv/Scripts/python.exe - macOS / Linux:
.venv/bin/python
如果你已经有一个装好 Pillow 的 Python,把 <PY> 换成它即可,跳过引导。
(也可以跑 python scripts/setup_env.py --check 做体检,或 --venv <已有venv路径> 指定。)
确认环境就绪后跑自检:
<PY> scripts/run_selftest.py --workdir <输出根>/_selftest
44 项断言,全绿再开始。若报缺 Pillow / numpy / ffmpeg,见 troubleshooting.md。
阶段 1:建任务目录
通用规则(所有机器适用):
- 优先
<当前工作区>/outputs/sticker-pack/<主题>-<MMDDHHMM>; - 拿不到工作区时退回
~/.sticker-pack/<主题>-<MMDDHHMM>; - 两者都不确定 → 直接问用户存哪,不要猜盘符。
若技能同目录存在
LOCAL.md,里面的「输出根目录」覆盖约定优先于上面的通用规则 (LOCAL.md不进版本库,仅本机私有,见仓库.gitignore)。
子目录固定:01_sheet/(母版)、02_cells/(静态素材)、03_gifs/(动效)、04_pack/(交付包)。
阶段 2:生成九宫格母版
这一步消耗图像生成额度(单张约 5–10 credits)。 每个会话第一次出图前用一句话说明消耗与张数,同一会话后续不再重复提示。
工具:任意支持「图生图(image-to-image) + 透明背景(alpha) + 1:1 正方形」 三种能力的图像生成工具。不同宿主参数名不同,但能力需求一致:
宿主 / 工具 原图字段 透明参数 尺寸 保真 / 参考强度 WorkBuddy ImageGenimage1background:"transparent"size:"1024x1024"input_fidelity:"high"OpenAI Images API image[]background:"transparent"size:"1024x1024"input_fidelity:"high"Gemini / 其它图生图模型 各自 image 字段 透明通道 正方形 高参考强度(保身份) input_fidelity之类字段不存在就不用传;关键是保住人物身份、表情、姿势、人数、构图,只换画风。- 若宿主不支持透明背景:仍按
references/prompts.md出图,但把"背景透明"改成 "纯色背景(如纯白 / 纯绿)",出图后用key_out.py --bg <背景色>本地抠成透明 (参见下方质量红线「无透明通道 / 棋盘格假透明」)。
提示词:取
references/prompts.md第 2 节的生产版。 如果后面只做静态、不打算切图/做动效,可以用第 1 节基础版。九格情绪:把用户的 9 个词替换进提示词里的 Emoji 位(或直接在"每个贴纸呈现不同的 表情、姿势或反应"后列出)。
出图后第一件事:验透明。 很多模型即使传了「透明背景」参数,也会回一张 画着灰白棋盘格的 RGB 图来"冒充"透明。
- 先看
mode是不是 RGBA,再数一下透明像素占比。 - 只要不是真 alpha(含"棋盘格假透明"),就先
key_out.py --bg auto抠一遍。 脚本会自动把棋盘格的两三种颜色都识别成背景一并删净,效果等同真 alpha。 - 不要把棋盘格母版直接丢给
slice_grid.py:它检测不到格缝,会走ALPHA_MISSING分支,切出来的格子带着棋盘格残底。
产出:真 alpha 直接落 01_sheet/sheet.png;否则先落 sheet_raw.png,
抠像后另存 sheet.png。
阶段 3:切分 + 质检
<PY> scripts/slice_grid.py \
--input 01_sheet/sheet.png --outdir 02_cells \
--labels "<九个名称>" --pad 6
不要平均切。 脚本用投影法找真实格缝,能处理格缝宽窄不一、九格不等宽高。
报告要读这几项:
| 项 | 含义 | 出现时怎么办 |
|---|---|---|
ALPHA_REAL |
母版有真实透明通道 | 正常 |
ALPHA_MISSING |
没有透明通道(含模型画的棋盘格假透明) | 用 key_out.py --bg auto 抠底,多色背景会被一起删掉 |
FAKE_ALPHA_CHECKERBOARD |
检测到多色背景 = 假透明棋盘格 | 属正常告警,已自动剔除;确认成品没有格纹残底即可 |
GAP_V_DIRTY / GAP_H_DIRTY |
格缝里有残留内容 | 重出母版把缝留宽;先看成品有没有被截断 |
CELL_BLEED |
某格内容贴到裁切边界 | 检查该格成品是否被切断 |
CELL_COUNT 不足 9 |
模型没排出 3×3 | 重出,不要用空格凑数 |
阶段 4:动效(可选,但大多数用户要)
两条路线,按用户偏好选。没说就默认走本地(稳、免费、透明干净)。
路线 A — 本地安全变换(默认)
<PY> scripts/animate.py \
--input 02_cells --outdir 03_gifs --fps 12 --duration 1.0 --size 240
九张自动匹配不同动作模板,首尾严格对齐、循环无跳帧。
默认 --scale-mode uniform:九格共用同一个缩放比,避免"身体画得短"的那几格
被放大成大头(源图里九个头本来是一样大的)。--scale-mode fit 是逐格适配,
只在九格本来就等高时才用。
参数含义、9 个模板的手感、调参边界见 references/motion-presets.md。
路线 B — AI 视频(效果更自然)
# B1 铺纯色幕(自动避开主体主色)
<PY> scripts/matte.py --input 02_cells --outdir 04_pack/matte --grid
# B2 把 04_pack/matte/sheet_matte.png 交给视频模型(提示词见 prompts.md 第 6 节)
# B3 视频拆格 + 逐帧抠像 + 出 GIF
<PY> scripts/video_split.py \
--input <产出的视频> --outdir 03_gifs --rows 3 --cols 3 --size 240 --fps 12
B 路线不要在视频提示词里写"背景保持透明"——输入已经是色幕, 且视频工具基本不输出 alpha,透明留到 B3 本地做更干净。
用户想两条都要 → 都跑,然后在报告里分别标注来源。
换风格时:回阶段 2 用同一张原图重出,不要在已风格化的图上二次转换。
Q 版家族(8 个)比例底座一致,差异在材质语言。首选用 chibi-pop;
想要一眼是风格化贴纸再换:
软糖糖果 → chibi-gummy;毛绒布偶 → chibi-fuzzy;机甲盒蛋 → chibi-mecha;
国潮剪纸 → chibi-papercut;随手速写 → chibi-sketch;通用 emoji → chibi-emoji3d;
积木拼装 → chibi-toy-brick。
已知易漂移的:chibi-fuzzy(头可能变熊脸)、chibi-papercut(可能被理解成贴纸边框)
——这两个的 body 已经显式加了身份锁定硬约束,使用时请保留该段或照抄。
风格查 / 拼提示词:
<PY> scripts/style_registry.py list # 看全部
<PY> scripts/style_registry.py resolve "毛绒绒" # 用户说法 -> key
<PY> scripts/style_registry.py compose --style chibi-gummy \
--identity "中国男性,黑色短寸平头,..." --labels "催更,收到,..."
阶段 5:平台适配 + 打包
<PY> scripts/pack.py \
--cells 02_cells --gifs 03_gifs --outdir 04_pack --platform wechat --zip
--platform 可选 wechat / qq / imessage / telegram / discord /
generic / all。用户提到多个平台就传 all。
产出:分平台目录、preview_static.png、preview_animated.png、
manifest.json、导入说明.md、<任务名>.zip。
体积超标时按这个顺序降级,不要一上来就压画质: 帧率 12→10→8 → 尺寸 240→200→160 → 时长 1.0→0.8→0.6。
阶段 6:交付
- 把成品图和 ZIP 交付给用户(不要只报路径)。
若宿主有"文件呈现 / 预览"工具就直接用;没有则在回复里附上绝对路径 + 关键指标。
优先呈现:
preview_static.png(一眼看到九格结果)、preview_animated.png、 一条代表性 GIF、04_pack/<任务名>.zip。 - 回复只写四样:匹配到的风格、九格名称、生成方式(本地/视频/两者)、 成品文件与体积是否达标。
- 在输出根目录追加一行到
ledger.md:时间 | 原图文件名 | 风格 | 静态/动态 | 平台 | 输出路径 - 不要把整段提示词贴进对话污染阅读,除非用户问。
阶段 7:桌面宠物(可选延伸)
用户说"做成桌面宠物 / pet / 挂在桌面上"时:
把 9 条 GIF 按固定文件名(idle.gif / running-right.gif / …)整理到一个目录,
文件名的映射表和提示词见 references/prompts.md 第 8 节。
官方入口是 ChatGPT 桌面端 Settings → Pets → Create your own pet。
产出铁律(违反即重做)
这三条是用户明确提过的要求,优先于任何风格描述:
- 画面里不许有任何数字。 九宫格是 3×3 排列,但绝不许给格子编号。
compose()已不再拼1 2 3…,并强制带【画面纯净——不要任何文字与编号】段。 自检 T11.13 / T11.14 守着这条,改提示词模板时别把它删了。 - 产物里不许出现原图。 原图只作为出图时的参考(
image1), 九格必须全部是同一套画风,不许留一格"真实照片抠像版"。references/prompts.md里那个"中间第 5 格放原图"的旧模板已废弃。 交付目录里也不要顺手把参考图复制进去。 - 本地画出来的图上也不许有数字(v1.4.1 补)。
素材文件名形如
01_催更.png,slice_grid按阅读顺序编号—— 但预览图上的标签必须剥掉这个序号前缀,只显示"催更"。 曾经pack.py::build_preview把文件名原样印上去,用户看到预览图 以为"表情包被画上了数字",实际是本地脚本写的。 现在统一走pack.display_name(),自检 T10.2 / T10.3 守着。 以后任何往图上画字的地方,都要先过display_name()。
质量红线
交付前逐条自查,有硬伤就重出/重跑,并向用户说明改了什么:
- 母版不是真透明 → 提示词里加重"背景透明、人物直接置于透明背景上", 或确认工具的透明背景参数真的传了。
- 人物边缘有白边/黑边 → 说明用了基础版提示词。换生产版。
- 九格被连成一幅连续画 → 提示词缺少
【表情包适配要求】段。 - 不同格子像不同的人 → 加重身份约束 + 把图生图保真度调到高。
- 有格子是空的 / 不足 9 格 → 重出母版,不做凑数。
- 抠像把白衬衫、浅发、同色道具打洞 → 用
--mode border-connected, 绝不用全局色键。 - 母版没有 alpha、背景是"画出来的灰白棋盘格" → 用
key_out.py --bg auto, 它会把多色背景一并删净。别把它当成"已经有透明通道"直接切图。 - 九格里有的头明显比别的大 → 逐格自动适配造成的假象。
animate.py/pack.py默认已改成九格共用缩放比,不要回退成--scale-mode fit。 - 打包后 GIF 看着几乎不动 →
reencode_gif被写成逐帧重新居中/贴底, 位移类动作被整体抵消。必须对整段帧序列用同一套仿射参数。 - 成品里多出一条莫名其妙的预览图或报告 → 素材目录里放了
_开头的内部文件。list_media已统一过滤,不要绕过它自己写os.listdir。 - 个别 GIF 总时长比别的长(比如 1280ms vs 960ms) → 重编码时在
seek循环之后才读duration,把最后一帧的时长套给了所有帧。 逐帧时长必须在循环里收,见references/motion-presets.md第 4 条。 - GIF 有拖尾 → 确认
disposal=2。 - 人物颜色不对但透明正常 →
paste(mask=)遮罩方向反了,见troubleshooting.md。 - 单一 GIF 超平台上限 → 按降级顺序调,
pack.py会点名是哪个文件。
脚本清单
全部在 scripts/,只用 Pillow(必需)+ numpy(可选加速)+ ffmpeg(仅视频路线)。
| 脚本 | 作用 |
|---|---|
common.py |
公共工具:遮罩、投影、画布归一化、报告 |
slice_grid.py |
九宫格母版 → 9 张透明素材 + 质检 |
matte.py |
透明素材 → 纯色幕 + 九宫格重排(自动避让主体主色) |
key_out.py |
边缘连通抠像(含 alpha 反混合与去溢色);支持多色背景,能处理模型画的"假透明棋盘格" |
animate.py |
本地安全变换 → 循环透明 GIF / WebP / APNG |
video_split.py |
宫格动作视频 → 9 段透明 GIF |
pack.py |
平台规格适配 + 预览图 + manifest + ZIP |
run_selftest.py |
44 项自检,不消耗额度,全绿再开工 |
make_test_sheet.py |
开发用:合成"不完美"九宫格母版 |
make_test_video.py |
开发用:合成 3×3 色幕视频供往返测试 |
参考文件
references/prompts.md— 八段可直接复用的提示词(母版两版、风格化、切图、 视频动效、拆格需求、桌面宠物)references/style-registry.md— 43 个风格 key(12 家族)+ 别名表 + 编译硬规则。 本文件由scripts/style_registry.py自动生成,请改脚本再render-md。scripts/style_registry.py— 风格单一数据源 + CLI:list / show / resolve / compose / validate / render-md / stats。references/motion-presets.md— 9 个动作模板参数表、两条动效路线对比、 平台规格、GIF 透明硬限制references/troubleshooting.md— 按「现象 → 原因 → 处理」组织的排错手册
授权与来源
工作流与提示词整理自公开的公开分享(DA / @zhidawang219555 的表情包系列教程), 本地实现、脚本、质检体系为原创。风格描述为原创特征描述, 不使用在世艺术家姓名或具体作品名作风格锚点,不声称复刻任何现成作品。 用户上传的肖像图仅用于生成用户自己的表情包,处理后不用于训练或再分发。