EIGHTfs/dsh-image-preview ↗★ 0
dsh-image-preview
DSH 会话内图片预览服务:把工作区图片通过 HTTP 暴露给会话渲染、文本→图片渲染(双字体防乱码)、SVG→PNG 转换。AI 在回复里贴 markdown 图片 URL,用户直接在对话中看图。
安装
$
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:EIGHTfs/dsh-image-preview说明文档
阅读完整 README ↗🖼️ 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 ` + `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`
## 📚 设计理念
1. **给用户的东西必须能打开**:地址一律用真实主机 IP(见 host-address-convention),不甩 127.0.0.1
2. **插件即服务**:服务随插件生命周期走,不需要用户手动起/停任何东西
3. **能力分层降级**:核心静态服务零依赖;文本渲染/SVG 转换依赖系统工具,缺失时优雅降级
4. **安全默认**:路径穿越防护 + 只读暴露,绝不给任意文件读取
## License
MIT