READMESource: main@618826c2
🖼️ dsh-image-preview
让 AI 在 DSH 会话里直接给你发图片 —— 静态图片服务 + 文本渲染 + SVG 转换,一条 API 全搞定
✨ 为什么需要它?
DSH 的 AI 会话回复是纯文本的,想让用户直接看到一张图片(截图、二维码、配图)时:
- ❌ 让用户去翻文件目录 —— 麻烦
- ❌ 手动起
python3 -m http.server—— 每次都要开服务、记端口 - ❌ 直接在 markdown 里写本地路径 —— GUI 渲染不了
dsh-image-preview 把这一切变成插件内置能力:AI 在回复里贴一个 markdown 图片 URL,用户直接在对话中看到图,无需任何手动操作。
📦 核心能力
| 接口 | 方法 | 说明 |
|---|---|---|
/api/image-preview/file?path=xxx |
GET | 静态图片服务:暴露工作区文件,AI 回复里贴 URL 即可渲染 |
/api/image-preview/render |
POST | 文本 → PNG:AI 把要展示的内容发给接口,生成图片 |
/api/image-preview/svg2png |
POST | SVG → PNG:GitHub 架构图等 SVG 转成可预览的 PNG |
/api/image-preview/status |
GET | 插件状态:版本 / workspace / Pillow 与字体可用性 |
用法示例
AI 回复里贴图(最常用):

渲染一段文字为图片:
curl -X POST http://127.0.0.1:3081/api/image-preview/render \
-H 'Content-Type: application/json' \
-d '{"text":"崩溃检测 ×2 全部正确检出","title":"实测记录","outPath":"report.png"}'
# → {"ok":true,"url":"/api/image-preview/file?path=report.png"}
SVG 架构图转 PNG:
curl -X POST http://127.0.0.1:3081/api/image-preview/svg2png \
-H 'Content-Type: application/json' \
-d '{"svgPath":"docs/screenshots/architecture.svg","outPath":"architecture.png","outputWidth":960}'
🛡️ 亮点设计
| 亮点 | 事实 |
|---|---|
| 双字体防乱码 | 中文用 Droid/Noto 等 CJK 字体、符号(→·×①等)用 DejaVu,逐字符渲染——不再出现"✅变方块" |
| emoji 兜底替换 | ✅→✓、🚀→>> 等,任何字体都没有的 emoji 自动转成可渲染文本 |
| 路径穿越防护 | 相对路径 normalize 后必须落在 workspace 内,../ 和绝对路径一律拒绝(实测防护通过) |
| 零运行时依赖 | 插件本身是纯 Node.js;渲染走系统 python3 + Pillow(可选),无 npm 依赖 |
| 纯服务端 | apply(ctx) 写法 + webServer 路由,无 client bundle,不碰 UI |
📦 安装
方式一:手动安装(三要素)
# 1. 源码放 node_modules_local
mkdir -p ~/.dsh/profiles/web/node_modules_local/dsh-image-preview
cp -r lib package.json cordis.patch.yml ~/.dsh/profiles/web/node_modules_local/dsh-image-preview/
# 2. package.json 加 file: 依赖
node -e "
const fs=require('fs');
const p=JSON.parse(fs.readFileSync('~/.dsh/profiles/web/package.json'));
p.dependencies['dsh-image-preview']='file:./node_modules_local/dsh-image-preview';
fs.writeFileSync('~/.dsh/profiles/web/package.json',JSON.stringify(p,null,2));
"
# 3. cordis.patch.yml 追加
cat >> ~/.dsh/profiles/web/cordis.patch.yml << 'EOF'
- insert:
- id: dsh-image-preview
name: dsh-image-preview
EOF
# 重启 DSH 生效
环境要求
- python3 + Pillow:文本渲染(
pip install pillow;本机沙箱只读时用pip install --break-system-packages --target <dir>+PYTHONPATH) - python3 + cairosvg:SVG 转换(依赖系统 librsvg)
- 都没有时插件仍可用:静态图片服务(/file)不依赖它们
🔧 工作原理
AI 会话回复 DSH 插件 用户
───────── ──────── ────
回复 markdown ──URL──▶ /api/image-preview/file ──▶ GUI 渲染图片
│
回复内容 ──▶ /api/image-preview/render ──生成 PNG──▶ 直接看到
│
SVG 路径 ──▶ /api/image-preview/svg2png ──转 PNG──▶ 直接看到
🧪 测试
| 测试 | 结果 |
|---|---|
| mock 单元测试(路由注册/路径穿越/渲染核心) | ✅ 9/9 通过 |
| 测试实例真机验证(3083) | ✅ 插件加载 + status/file/render/svg2png 全接口通过 |
| 路径穿越防护 | ✅ ../secret 与绝对路径均被拒绝(400) |
| 双字体符号渲染 | ✅ ✅→① 等符号无乱码 |
运行测试:node test-apply.mjs
📚 设计理念
- 给用户的东西必须能打开:地址一律用真实主机 IP(见 host-address-convention),不甩 127.0.0.1
- 插件即服务:服务随插件生命周期走,不需要用户手动起/停任何东西
- 能力分层降级:核心静态服务零依赖;文本渲染/SVG 转换依赖系统工具,缺失时优雅降级
- 安全默认:路径穿越防护 + 只读暴露,绝不给任意文件读取
License
MIT
No comments yet. Be the first to write one.