我写了个 Claude Code Skill,再也不用手动切图传 COS 了
切图、压缩、传 COS、复制链接、粘回代码。一个页面 5 张图就要重复 5 遍。我受够了,写了个 Skill 把这活儿交给 AI。
起因:每天在 Figma 和 COS 控制台之间反复横跳
我做小程序开发,日常跟设计师对接。每次拿到 Figma 设计稿,写代码之前得先处理图片:
- Figma 里一张张切图导出
- 打开 TinyPNG 网站,把 PNG 拖进去压缩
- 登录腾讯云 COS 控制台,上传
- 复制 CDN 链接,粘到代码里
- 下一张,重复
一个页面 5 张图,这套操作就要走 5 遍。说实话,这活儿谁干谁烦。
后来我发现 Claude Code 有个 Skill 机制,可以教它执行自定义流程。花了2小时折腾出来一个 image-auto-upload Skill,现在图片这块基本不用我操心了。
效果直接看下面的图片
截图里能看到整个链路:
- 左上角是 Figma 设计稿
- 左侧终端里 Claude Code 在自动识别图片素材
- 中间是tinypng压缩 + 上传 COS 的过程
- 右上角 COS 控制台里文件已经上传成成功
- 右下角是小程序里的最终效果
我就输入了一句"根据 Figma 设计稿实现这个页面(自行切图上传替换)",它自己全办了。
Skill 是个什么东西
简单说,Skill 就是一个文件夹,放在 .claude/skills/ 下面,里面告诉 Claude 怎么完成某个特定任务。
Claude Code 本身能读代码、写代码、跑命令,但它不知道你们项目的图片要传到哪个 COS Bucket,不知道 PNG 要先压缩,不知道上传路径的前缀规则。这些"项目私货",你得自己教它。Skill 就是干这个的。
目录结构长这样:
.claude/skills/image-auto-upload/
├── SKILL.md # 给 Claude 看的操作手册
├── README.md # 给人看的使用文档
├── resources/ # 放待上传的图片
│ └── README.md
└── scripts/ # 执行脚本
├── upload_images.cjs # Node.js 上传脚本
└── compress_png.py # Python 压缩脚本
最核心的是 SKILL.md。Claude 读这个文件来理解:什么时候该用这个技能、具体怎么操作、调什么脚本、结果怎么展示。
SKILL.md 怎么写
这个文件写得好不好,直接决定 Claude 能不能正确干活。我拆开讲讲。
触发场景
## 触发场景
### 场景 1:Figma 设计稿实现
当根据 Figma 设计稿实现页面时,如果设计稿中包含图片素材:
1. 列出可上传的图片素材(图片名称、类型、用途)
2. 等待用户确认需要上传哪些图片
3. 执行上传并返回 CDN URL
### 场景 2:直接上传
当用户直接告知需要上传的图片或图片文件夹时,直接执行上传流程。
两种触发方式。一种是实现 Figma 设计稿时 Claude 自己发现有图片,会先问你要不要上传;另一种是你直接说"上传图片",它立刻执行。
我一开始只写了第二种,后来发现配合 Figma Agent 用的时候,Claude 不知道该主动处理图片,还得我手动提醒。加上第一种之后就顺畅了。
处理流程
将图片放入 resources/ 文件夹
│
▼
是图片文件?(png/jpg/jpeg/webp/gif/svg)
│
┌───┴───┐
YES NO → 跳过
│
▼
是 PNG 格式?
┌───┴───┐
YES NO
│ │
▼ │
自动压缩 │
│ │
└───┬───┘
│
▼
上传到 Tencent COS
│
▼
返回 CDN URL
│
▼
自动清理源文件
几个设计上的考虑:
- PNG 先过 TinyPNG API 压缩再传,JPG/WebP 直接传。PNG 压缩率一般在 60%-80%,省的流量还是挺可观的
-
.DS_Store之类的杂文件自动跳过,不用手动清理 - 传完自动删源文件。一开始我没加这个,resources 目录越来越大,后来加了自动清理
输出格式
| 图片名称 | CDN URL |
|----------|---------|
| icon.png | https://xxx.cos.ap-nanjing.myqcloud.com/applet/icon.png |
| bg.jpg | https://xxx.cos.ap-nanjing.myqcloud.com/applet/bg.jpg |
上传完用表格展示结果,方便直接复制 URL。
两个脚本,一个压缩一个传
整个 Skill 靠两个脚本干活。
PNG 压缩(compress_png.py)
import tinify
def compress_image(input_path, output_path=None):
tinify.key = TINYPNG_API_KEY # 从 .env.skills 读取
input_size = input_file.stat().st_size
source = tinify.from_file(str(input_file))
source.to_file(str(output_path)) # 压缩后覆盖原文件
output_size = output_path.stat().st_size
compression_ratio = round((1 - output_size / input_size) * 100, 2)
return { "compression_ratio": compression_ratio }
逻辑很直白:读文件、调 TinyPNG API、写回去覆盖原文件。TinyPNG 免费额度每月 500 次,个人项目完全够用。
COS 上传(upload_images.cjs)
const COS = require('cos-nodejs-sdk-v5');
// 上传单个文件(分片上传)
function uploadFile(filePath, key) {
// 1. 初始化分片上传
cos.multipartInit({ Bucket, Region, Key }, (err, data) => {
// 2. 上传分片
cos.multipartUpload({ ... Body: fs.createReadStream(filePath) }, () => {
// 3. 完成上传
cos.multipartComplete({ ... });
});
});
}
// 上传整个文件夹(递归子目录)
async function uploadFolder(folderPath, prefix) {
for (const file of files) {
if (!isImageFile(file)) continue; // 跳过非图片
compressPng(file); // PNG 先压缩
await uploadFile(file, key); // 传到 COS
fs.unlinkSync(file); // 删源文件
}
}
用了 COS SDK 的分片上传,支持递归子目录。上传成功删源文件,失败的留着方便重试。
密钥放哪
COS 密钥和 TinyPNG API Key 放在项目根目录的 .env.skills 里:
# .env.skills(记得加 .gitignore)
COS_BUCKET=your-bucket-name
COS_REGION=ap-nanjing
COS_UPLOAD_PREFIX=applet
TINYPNG_API_KEY=your-tinypng-api-key
这个文件不进 Git,密钥不会泄露。
实际用起来是什么感觉
配合 Figma 用(我最常用的方式)
我项目里还有个 figma-designer Agent,配置里写了一条:
遇到图片,先自动切到本地,然后调用 skills 进行压缩上传 COS,然后替换代码
所以流程是这样的:
- 我在 Figma 里选中要实现的页面
- 在 Claude Code 里说"根据 Figma 设计稿实现这个页面"
- Claude 通过 Figma MCP 读设计稿,识别出图片素材
- 自动导出图片 → 压缩 PNG → 传 COS → 拿到 CDN URL
- 用 URL 替换代码里的图片引用,生成 Vue 组件
我只管最后看一眼代码对不对。中间图片那一堆事,完全不用管。
说实话第一次跑通的时候还挺意外的,没想到几个工具串起来能这么顺。
手动传几张图
有时候设计师单独丢几张图过来,不走 Figma 流程:
我:帮我上传 resources 里的图片
Claude:发现 resources 目录下有 3 张图片:
- banner.png (PNG,将自动压缩)
- icon-success.png (PNG,将自动压缩)
- photo.jpg (JPG,直接上传)
正在处理...
[banner.png] 正在压缩 PNG... 压缩完成 (72% reduction)
[banner.png] 上传完成
[icon-success.png] 正在压缩 PNG... 压缩完成 (65% reduction)
[icon-success.png] 上传完成
[photo.jpg] 上传完成
========== 上传完成 ==========
成功: 3 个文件
失败: 0 个文件
| 图片名称 | CDN URL |
|----------|---------|
| banner.png | https://xxx.cos.../applet/banner.png |
| icon-success.png | https://xxx.cos.../applet/icon-success.png |
| photo.jpg | https://xxx.cos.../applet/photo.jpg |
源文件已自动清理。
批量传一整套图
比如一次性传一套图标:
resources/
├── icons/
│ ├── home.png
│ ├── cart.png
│ └── user.png
└── backgrounds/
├── login-bg.jpg
└── main-bg.jpg
上传后目录结构原样保留:
applet/icons/home.png
applet/icons/cart.png
applet/icons/user.png
applet/backgrounds/login-bg.jpg
applet/backgrounds/main-bg.jpg
这个我踩过坑。一开始上传脚本不支持子目录,所有文件都平铺到根路径下,文件名一冲突就覆盖了。后来加了递归目录支持才解决。
想自己搞一个?照着来
1. 建目录
mkdir -p .claude/skills/image-auto-upload/{scripts,resources}
2. 装依赖
# PNG 压缩
pip install tinify
# COS 上传
npm install cos-nodejs-sdk-v5
3. 配环境变量
项目根目录建 .env.skills:
COS_BUCKET=your-bucket-name
COS_REGION=ap-nanjing
COS_UPLOAD_PREFIX=your-prefix
TINYPNG_API_KEY=your-tinypng-api-key
TinyPNG API Key 去 tinypng.com/developers 申请,免费的,每月 500 次额度。
4. 写 SKILL.md
这步最花时间,也最值得花时间。几个经验:
- 触发场景写清楚,不然 Claude 不知道什么时候该用
- 流程用流程图或步骤列表,别写大段文字
- 命令给完整的,能直接复制执行的那种
- 定义好输出格式,不然每次返回的结果格式都不一样
我第一版 SKILL.md 写得太简略,Claude 经常漏步骤。后来补了流程图和具体命令,就稳定多了。
5. 加 .gitignore
echo ".env.skills" >> .gitignore
echo ".claude/skills/image-auto-upload/resources/*" >> .gitignore
echo "!.claude/skills/image-auto-upload/resources/README.md" >> .gitignore
到底省了多少事
列个对比吧:
| 操作 | 手动 | 用 Skill |
|---|---|---|
| 切图导出 | 一张张从 Figma 导出 | 自动识别导出 |
| PNG 压缩 | 开 TinyPNG 网站拖拽 | 自动调 API |
| 上传 COS | 登控制台手动传 | 脚本自动传 |
| 复制链接 | 一个个复制 URL | 表格直接给 |
| 替换代码 | 手动粘贴 | 自动替换 |
| 5 张图耗时 | 大概 10 分钟 | 30 秒左右 |
代码量也不大,Python 脚本 136 行,Node.js 脚本 290 行。写 SKILL.md 反而花的时间更多,因为要反复调试 Claude 的理解是否准确。
说到底,Skill 就是把你脑子里"这个项目图片该怎么处理"的经验,写成 Claude 能看懂的文档。教一次,后面就不用再操心了。
如果你项目里也有类似的重复操作,可以试试写个 Skill。不一定是图片上传,任何有固定流程的事情都行。