截图标注工具箱
把"发截图 + 一句话标注需求"直接变成标注完成的 PNG 成品。用户说"把这里圈出来 / 标个箭头 / 把手机号打码"时,由你把自然语言翻译成坐标和操作 JSON,调用 scripts/annotate.py 一次执行全部标注,交付文件路径即可。
功能一览
| type | 效果 | 必填字段 | 可选字段 | 说明 |
|---|---|---|---|---|
arrow |
箭头(线段+实心三角头) | from [x1,y1]、to [x2,y2] |
color、width |
从起点指向终点,to 端是箭头尖 |
rect |
矩形框 | box [x,y,w,h] |
color、width |
w/h 是宽高,不是右下角坐标 |
ellipse |
椭圆圈 | box [x,y,w,h] |
color、width |
内切于 box 的椭圆 |
text |
文字标注 | pos [x,y]、content |
size(默认 36)、color |
pos 是文字左上角,中文字体自动加载 |
number |
序号圆标 | pos [x,y] |
n(默认 1)、size(默认 24)、color |
实心圆底 + 白色数字,pos 是圆心 |
mosaic |
马赛克 | box |
size(块大小,默认 12) |
区域分块打码,不可还原 |
blur |
高斯模糊 | box |
radius(默认 8) |
区域模糊,弱于马赛克,慎用于敏感信息 |
crop |
裁剪 | box |
— | 输出只保留 box 区域,通常单独用 |
所有坐标为像素,原点在左上角;颜色支持 #RRGGBB 或颜色名(如 red);默认标注色 #FF3B30(醒目红)。
工作流程
- 拿到输入:确认待标注图片的本地路径。用户只发了截图描述而没给文件时,先让用户提供文件;原图始终不被修改,输出写到新文件。
- 把"这里"翻译成坐标:用户几乎不会给精确坐标,需要推断:
- 用python3 -c "from PIL import Image; im=Image.open('in.png'); print(im.size)"获取图片尺寸;
- 结合用户描述("右下角按钮""第二段文字""头像那里")和截图常见布局(顶部标题栏、左侧导航、正文区、右下操作按钮)估算坐标;
- 拿不准时先用crop裁出疑似区域让用户确认,或先标注一版、明确告知用户"如果圈的位置偏了,告诉我往哪边挪"。 - 选择模式:一次要 2 个及以上标注 → JSON 多操作模式(
--ops);只有打码/模糊/裁剪等单一常用操作 → 快捷单操作模式。 - 执行命令(见下方命令参考)。
- 验收交付:检查 stderr 是否有越界
[警告];向用户报告输出文件绝对路径、做了哪些标注;需要调整就改坐标重跑,不修改已生成的文件。
命令参考
脚本位置:<技能目录>/scripts/annotate.py
模式一:JSON 多操作(一次执行多个标注)
python3 "${SKILL_DIR:-$PWD/.workbuddy/skills/image-annotate-toolbox}/scripts/annotate.py" in.png --ops '[
{"type":"arrow","from":[420,180],"to":[500,240],"color":"#FF3B30","width":5},
{"type":"ellipse","box":[470,620,260,60],"color":"#FF3B30","width":5},
{"type":"text","pos":[470,585],"content":"注意这里","size":36,"color":"#FF3B30"},
{"type":"number","pos":[1100,120],"n":1},
{"type":"number","pos":[1100,180],"n":2},
{"type":"mosaic","box":[200,640,180,120],"size":12},
{"type":"blur","box":[400,640,180,120],"radius":8}
]' -o out.png
- 操作按数组顺序执行;超长 JSON 可先写入文件,再用
--ops @ops.json传入; --ops与快捷单操作同时给出时,以--ops为准(会提示);- JSON 必须双引号,漏逗号/中文引号会报"JSON 解析失败"并附格式示例。
模式二:快捷单操作(常用场景免写 JSON)
# 打码(最常用)
python3 .../annotate.py in.png mosaic --box 100,200,300,150 -o out.png
# 区域模糊
python3 .../annotate.py in.png blur --box 100,200,300,150 --radius 8
# 裁剪(通常单独用)
python3 .../annotate.py in.png crop --box 0,0,600,400 -o part.png
# 箭头 / 矩形 / 椭圆 / 文字 / 序号
python3 .../annotate.py in.png arrow --from 100,100 --to 300,200
python3 .../annotate.py in.png rect --box 100,200,300,150 --color #FF3B30 --width 5
python3 .../annotate.py in.png ellipse --box 100,200,300,150
python3 .../annotate.py in.png text --pos 100,160 --content "注意这里" --size 36
python3 .../annotate.py in.png number --pos 1100,120 --n 1
其他参数
-o/--output:输出 PNG 路径,默认<输入名>_annotated.png;--font:中文字体路径(默认自动查找 Noto Sans SC,也可用环境变量ANNOTATE_FONT);--width线宽(默认 5)、--size字号(text 36 / number 24)、--block-size马赛克块(快捷模式用,避免与字号冲突)、--radius模糊半径;--help查看全部参数与示例。
示例对话
例 1:打码
> 用户:这张聊天截图里手机号帮忙打一下码,别让人看出来 [附截图]
>
> 你:图片尺寸是 1080×1440,手机号在正文第三行(约 y=620 起)。我按你描述的位置打码:
> python3 .../annotate.py chat.png mosaic --box 180,600,420,60 -o chat_annotated.png
> 已完成,马赛克不可还原,输出文件:/path/chat_annotated.png。如果遮的位置不对,告诉我往哪边挪。
例 2:多标注一次完成
> 用户:把表格里超支的那一行圈出来,加个箭头写"这里",右上角标个①,左下角二维码糊掉
>
> 你:一次执行 4 个操作:
> bash
> python3 .../annotate.py report.png --ops '[
> {"type":"rect","box":[210,436,760,42]},
> {"type":"arrow","from":[520,300],"to":[300,450]},
> {"type":"text","pos":[530,270],"content":"这里","size":36},
> {"type":"mosaic","box":[40,700,160,80]}
> ]' -o report_annotated.png
>
> 说明:用矩形圈行、箭头从文字指向该行、左下角二维码已打码。文件在 .../report_annotated.png。
例 3:只裁剪
> 用户:只要这张图上半部分
>
> 你:python3 .../annotate.py shot.png crop --box 0,0,1200,400 -o top.png,已裁出顶部 1200×400 区域:/path/top.png。
运行环境
- 脚本:
scripts/annotate.py(相对技能根目录) - Python:3.9+
- 第三方库:
Pillow(pip install Pillow)
开工前先跑一次自检,缺什么当场补,别等跑到一半报错:
python3 -c "import PIL" 2>/dev/null || echo "缺 Pillow,请执行 pip install Pillow"
> 缺依赖时用中文告诉用户缺什么、装完就能用,不要把 Python 的英文 traceback 原样贴给用户。
注意事项
- 坐标全是像素、原点在左上角;
box是[x, y, 宽, 高]。坐标越界不会报错中断,会在 stderr 输出[警告]并自动裁剪到图内,交付前务必检查。 - 打码(mosaic)不可逆,块内像素完全一致,无法还原;涉及手机号、身份证、密钥等敏感信息优先用 mosaic 而非 blur(blur 只是模糊,存在被反推的风险),且 box 要完整覆盖目标并稍留边距。
- crop 通常单独用:它之后若还有操作,坐标会基于裁剪后的新图,脚本会给出警告提醒。
- 输出一律为 PNG,标注线条清晰不失真;输入原图不会被改动。
- 操作顺序即数组顺序,后画的覆盖先画的;同一区域又圈又打码时,把打码放在前面才不会被框线压住。
- 文字默认字号 36 在 1200px 宽的截图上比较醒目;小截图可调小,长文字建议缩写,避免遮挡关键内容。
- 依赖:Pillow(≥10)与系统中的中文字体;当前环境字体位于
/usr/local/share/fonts/custom/NotoSansSC-Regular.ttf,脚本会自动查找。