# image-compress > 博客图片自动 WebP 转换。支持文章(Markdown)和 Prompt(TypeScript)两种类型的图片转换。扫描图片引用,转换非 WebP 格式,更新引用并清理旧文件。支持 PNG、JPG、JPEG、BMP、TIFF、TIF、GIF 转 WebP,可控制压缩质量。当用户请求图片格式转换或压缩时调用该 skill。 - Author: zengyq - Repository: zeng-yq/Astro-Blog - Version: 20260123050003 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-07 - Source: https://github.com/zeng-yq/Astro-Blog - Web: https://mule.run/skillshub/@@zeng-yq/Astro-Blog~image-compress:20260123050003 --- --- name: image-compress description: 博客图片自动 WebP 转换。支持文章(Markdown)和 Prompt(TypeScript)两种类型的图片转换。扫描图片引用,转换非 WebP 格式,更新引用并清理旧文件。支持 PNG、JPG、JPEG、BMP、TIFF、TIF、GIF 转 WebP,可控制压缩质量。当用户请求图片格式转换或压缩时调用该 skill。 --- # Image Compress 为博客文章和 Prompt 自动转换图片为 WebP 格式并优化图片加载性能。 ## How to Use This Skill 当用户请求压缩图片时,按以下流程执行: ### Step 0: 识别内容类型 根据用户输入自动识别内容类型: | 类型标识 | 关键词 | 文件特征 | 路径特征 | | ------------ | ----------------------- | -------- | ------------------------ | | **文章** | 文章、blog、post | .md | src/content/blog/ | | **Prompt** | 提示词、prompt、prompts | .ts | src/page_data/Prompts.ts | | **无法识别** | - | - | 询问用户确认 | ### Step 1: 识别目标内容 - **对于文章**,用户可以指定文章的方式: - **文件路径** - **文章标题关键词** - **对于 Prompt**,用户可以指定 Prompt 的方式: - **Prompt 标题关键词** ### Step 2: 扫描图片引用 **对于文章**,解析文章文件,提取所有图片引用: - Frontmatter 中的 `cover` 字段 - Markdown 正文中的 `![描述](路径)` 语法 **对于 Prompt**,解析 Prompts.ts,提取 Prompt 的 `images` 数组: - 定位目标 Prompt(通过 ID 或标题) - 提取 images 数组中的所有路径 - 格式:`['/assets/images/prompts/xxx.png', ...]` ### Step 3: 过滤非 WebP 图片 检查引用图片的文件扩展名,识别需要转换的图片: - **需要转换**: `.png`, `.jpg`, `.jpeg`, `.bmp`, `.tiff`, `.tif`, `.gif` - **无需转换**: `.webp`, `.svg`, `.avif` ### Step 4: 转换图片 对每个非 WebP 图片调用 Python 脚本进行转换: ```bash python3 .claude/skills/image-compress/scripts/convert_to_webp.py \ "public/图片路径.png" \ --quality 90 ``` ### Step 5: 更新图片引用/数据 - 对于**文章**: - **Frontmatter**: 更新 `cover` 字段的扩展名 - **正文**: 更新 Markdown 图片语法的路径 - 对于**Prompt**: - 更新 `src/page_data/Prompts.ts` 中数据 使用 Edit 工具进行精确修改。 ### Step 6: 清理旧文件 删除已成功转换的原始图片文件。 --- ## Output Format 转换完成后,按照以下示例输出转换结果: ```markdown ## 转换结果 **文章/Prompt**: xxxxx ### 封面图 - ✅ gemini-education-offer-banner.png → WebP - 原始: 245 KB | 压缩后: 112 KB | 节省: 54.3% ### 正文图片 - ✅ gemini-enterprise-registration-page.png → WebP - 原始: 156 KB | 压缩后: 68 KB | 节省: 56.4% - ✅ gemini-30-day-trial-button.png → WebP - 原始: 89 KB | 压缩后: 42 KB | 节省: 52.8% ### 汇总 - 处理图片: 7 张 - 原始总大小: 1.04 MB - 压缩后总大小: 472 KB - **总节省: 54.6%** ``` --- ## Common Rules ### 文件路径处理 | 规则 | 说明 | 示例 | | ------------------ | -------------------------- | ----------------------------------- | | **文章路径优先** | 用户提供完整路径时直接使用 | `src/content/blog/xxx.md` | | **Prompt 路径** | Prompts.ts 文件路径 | `src/page_data/Prompts.ts` | | **文章 ID 匹配** | 通过 `id` 字段查找文章 | `gemini-3-pro-enterprise-guide` | | **Prompt ID 匹配** | 通过 `id` 字段查找 Prompt | `prompt-001` | | **标题匹配** | 使用 Grep 搜索标题关键词 | "荣耀碎片" 或 "Gemini 教育" | | **相对路径转绝对** | 路径需加 `public/` 前缀 | `/assets/...` → `public/assets/...` | ### 转换安全规则 | 规则 | 说明 | | ------------------- | ------------------------------ | | **转换前验证** | 确认源文件存在且可读 | | **WebP 存在则跳过** | 目标 WebP 已存在时询问是否覆盖 | | **保留原文件** | 默认删除,`--keep-old` 时保留 | | **质量范围检查** | quality 参数必须在 0-100 之间 | | **失败回滚** | 转换失败时保留原始文件 | ### 文章引用更新 | 场景 | 处理方式 | | --------------------- | ----------------------------------------- | | **Frontmatter cover** | 替换路径的扩展名部分 | | **Markdown 图片** | 正则替换 `!\[.*\]\((.*\.png)\)` → `.webp` | | **多次引用同一图** | 批量替换所有出现位置 | | **外部链接图片** | 跳过,不处理 | ### Prompt 引用更新 | 场景 | 处理方式 | | --------------------- | ------------------------------- | | **images 数组** | 替换数组中每个路径的扩展名 | | **单图更新** | 逐个更新,避免批量替换错误 | | **保留 content 字段** | 不修改 content 字段中的文本内容 | | **TypeScript 语法** | 确保引号、逗号、括号正确配对 | --- ## Error Handling ### 文件未找到 ```markdown **错误**: 文章文件不存在 - 提供的路径: src/content/blog/不存在的文章.md - 建议: 使用 Glob 搜索可用文章 ``` ### 图片文件缺失 ```markdown **警告**: 引用的图片文件不存在 - 文章中引用: /assets/images/articles/xxx/缺失的图片.png - 实际路径: public/assets/images/articles/xxx/缺失的图片.png - 建议: 检查图片路径或删除无效引用 ``` ### 转换失败 ```markdown **错误**: 图片转换失败 - 文件: public/assets/images/articles/xxx/损坏的图片.png - 原因: Pillow 无法读取该文件 - 建议: 检查文件完整性或使用备用图片 ``` ### 文件权限错误 ```markdown **错误**: 无法删除原始文件 - 文件: public/assets/images/articles/xxx/图片.png - 原因: 文件被占用或权限不足 - 建议: 手动删除文件或使用 --keep-old 选项 ``` ### TypeScript 文件错误 ```markdown **错误**: Prompts.ts 语法错误 - 文件: src/page_data/Prompts.ts - 原因: 更新后数组结构损坏 - 建议: 检查引号和逗号配对,恢复备份 ``` ### Prompt 数据未找到 ```markdown **错误**: 无法找到指定的 Prompt - 搜索关键词: xxx - 可用的 Prompt: prompt-001: 荣耀碎片致敬海报 - 建议: 使用正确的 ID 或标题 ``` --- ## Safety Checks ### 转换前检查清单 **文章**: - [ ] 确认文章文件存在且可读 - [ ] 提取所有图片引用(封面 + 正文) - [ ] 验证图片文件存在于文件系统 - [ ] 确认 WebP 文件不存在(或询问覆盖) - [ ] 验证 Python 脚本可执行 **Prompt**: - [ ] 确认 Prompts.ts 文件存在且可读 - [ ] 找到目标 Prompt(通过 ID 或标题) - [ ] 提取 images 数组中的所有路径 - [ ] 验证图片文件存在于文件系统 - [ ] 确认 WebP 文件不存在(或询问覆盖) - [ ] 验证 Python 脚本可执行 ### 更新前检查清单 **文章**: - [ ] 所有图片转换成功 - [ ] 验证生成的 WebP 文件可读 - [ ] 备份原始文章内容(可选) - [ ] 确认更新影响范围(Frontmatter + 正文) **Prompt**: - [ ] 所有图片转换成功 - [ ] 验证生成的 WebP 文件可读 - [ ] 备份 Prompts.ts 原文件 - [ ] 确认更新只影响 images 数组 - [ ] 验证 TypeScript 语法正确 ### 删除前检查清单 - [ ] WebP 文件大小合理(非 0 字节) - [ ] 可以打开 WebP 文件验证完整性 - [ ] 文章引用已更新为 WebP - [ ] 用户未指定 `--keep-old` --- ## Pre-Delivery Checklist ### 转换完整性 **文章**: - [ ] 所有非 WebP 图片已转换 - [ ] 文章中所有图片引用已更新 - [ ] 原始图片文件已删除(除非指定保留) - [ ] 封面图和正文图片都已处理 **Prompt**: - [ ] 所有非 WebP 图片已转换 - [ ] Prompts.ts 中 images 数组已更新 - [ ] 原始图片文件已删除(除非指定保留) - [ ] content 字段未被修改