图片裁剪合成工具
一、触发场景(命中即自动进引导流程)
| 用户说 | 走哪个模式 |
|---|---|
| 把 A 图某部分贴到 B 图 / 截图拼接 / 局部复制 | 模式1 |
| 裁剪、抠图、去掉页眉水印边距 | 模式1 |
| 框选、可视化选区域、手动画框 | 模式2 |
二、硬规则(违反即失败)
- 禁止要用户输坐标、百分比或命令,只让他说人话。
- 一次只问一个问题,得到答复再进下一步。
- 脚本由你拼接执行,不把命令展示给用户。
- 🔴 CHECKPOINT:裁剪、粘贴每步必须先出预览图并停下等"可以",禁止连跑两步。
- 微调按 10px 或 10% 步进;单轮最多 3 次,第 4 次改让用户在图上标两点(转模式2)。
- 🔴 禁止
--output与--input/--background同路径(脚本会拒绝并 exit 2)。
三、模式1:分步迭代(默认)
| 步 | 你做什么 | 产物 |
|---|---|---|
| 1 | 问源图路径(只有要粘贴时才再问目标图);用 Read 确认文件存在 | 已存在的绝对路径 |
| 2 | 问裁剪区域("上半部分""左侧30%""去掉顶部页眉"),解析成 --box,跑 crop |
<源图目录>/.preview_crop_1.png |
| 3 | 展示预览 → 问"可以吗";微调则重算 box,预览序号 +1 | 更新后的预览 |
| 4 | 问粘贴位置("右下角""正中间""留20像素"),跑 paste;前景大于底图时先加 --resize-width |
<目标图目录>/.preview_paste_1.png |
| 5 | 展示预览 → 确认后存正式文件,告知绝对路径 | 最终成品 |
> 只要裁剪、不要粘贴(去页眉、去水印边距、抠图):做完第 3 步就结束,跳过第 4-5 步,直接存正式文件,别问"要贴到哪张图"。
> 收尾时删除本轮生成的 .preview_* 临时文件;用户要求保留则明确告知其所在目录。
四、模式2:红点标记框选
- 给指引:用系统「画图」打开源图 → 纯红
#FF0000画笔 → 在区域左上角和右下角各画一个点(直径 ≥5px)→ 存图上传。 - 跑
detect拿坐标 → 用该 box 跑crop出预览 → 🔴 停下确认。 - 粘贴位置仍用方位描述,或对目标图重复一次红点标记。
五、命令(自行拼接,勿展示)
> 路径以本技能目录为基准,勿用当前工作目录的相对路径。
> 需 Python 3 + Pillow(python -m pip install Pillow,缺库时脚本会中文提示并退出 2);macOS/Linux 用 python3。
python <技能目录>/scripts/image_editor.py crop --input 源图 --output 预览 --box "左,上,右,下" --unit pixel|percent
python <技能目录>/scripts/image_editor.py paste --background 底图 --foreground 前景 --output 输出 --anchor top-left|top-right|bottom-left|bottom-right|center --position "x,y" --resize-width 宽度
python <技能目录>/scripts/dot_detector.py --input 已标记图
detect 成功时 stdout 只输出 left,top,right,bottom,警告走 stderr;退出码 0 成功 / 1 未识别到合格两点 / 2 参数或文件错误。detect 另可调 --r-min / --gb-max / --dom / --min-area,默认值见 §八。
六、失败模式(每步失败后先查此表)
| 症状(stderr / 退出码) | 一线修复 | 仍失败兜底 |
|---|---|---|
| exit 2「源图片不存在」 | 让用户重发,或核对路径拼写 | 用 Read 打印实际目录列表让用户指认 |
| exit 2「裁剪框超出图片范围」 | 按报错里的合法范围重算 box | 报图片真实尺寸,请用户重新描述区域 |
| exit 2「裁剪框无效:右必须>左」 | 方向搞反了,按左上原点重算 | 无条件改成"全图裁一半"再微调 |
| exit 2「resize-width 超出容纳上限」 | 用报错给出的最大可用宽度 | 去掉 --resize-width 按原尺寸贴 |
| exit 2「粘贴位置越界」 | 减小 --position 或换 --anchor |
前景比底图大:按报错给出的「最大可用宽度」加 --resize-width 再贴 |
| exit 2「不是可识别的图片」 | 请用户另存为 png/jpg | 用系统截图重截一张 |
| exit 1「未识别到纯红色标记」 | 提示换纯红 #FF0000、加粗画笔 |
放弃红点,转模式1 用语言描述 |
| exit 1「只识别到 1 个合格红点」 | 按报错里每个红块给出的判废原因改(面积超限/长宽比不像圆点) | 转模式1 |
| exit 1「红色像素过多」 | 只截取目标区域再标记 | 转模式1 用语言描述 |
| exit 2「输出文件扩展名不支持」 | 换 .png(保透明)或 .jpg(自动拍平透明通道) |
用 <原名>_out.png 重出 |
| WARN「识别到 N 个红块」 | 图里有其他红色元素,提示去掉后重传 | 警告不等于失败:先用当前坐标出预览让用户判断 |
| 预览图打开是空白/全黑 | 检查 box 是否退化为 1px 宽 | 回到第 2 步重新取区域 |
七、反例黑名单(不要做)
- ❌ 拿
--output覆盖原图"省一步"——会毁掉用户素材。 - ❌ 用户没确认裁剪效果就直接贴图(违反 CHECKPOINT)。
- ❌ 把命令行贴给用户让他自己跑。
- ❌ 红点模式里"目测"坐标并宣称识别成功——必须真跑
detect看 stdout。 - ❌ 一次抛出多个问题("图在哪、要裁哪、贴哪")。
- ❌ 把 stderr 的 WARN 当报错重做整个流程。
八、判定阈值与退出码
| 参数 | 默认 | 含义 |
|---|---|---|
--r-min |
200 | 红通道下限 |
--gb-max |
80 | 绿/蓝通道上限 |
--dom |
100 | 红色主导度 r-max(g,b),滤掉暗红/棕红 |
--min-area |
9 | 单个红点最小像素数;上限为图面积的 8% |
两点中心距 <10px 判为重合、直接失败。识别到多于 2 块时按"最左上 + 最右下"取值并在 stderr 警告;红色像素总数 >20 万判定为整图偏红、直接拒绝。