koishi-plugin-quote-debug-msg-json-image
v0.2.0-beta.8
Published
📋把一条消息的数据结构用json/yaml/toml的格式渲染成图片,🎨支持typst或者markdown。还支持用puppeteer渲染onebot的合并转发成图片🖼️
Downloads
117
Readme

📋 koishi-plugin-quote-debug-msg-json-image
回复一条消息,将其渲染为精美的 JSON/YAML/TOML 格式图片(防止超出聊天平台的文字长度上限)。还支持渲染 OneBot 的合并转发消息为图片。
✨ 功能特性
- 📋 dump 指令:将消息对象序列化为 JSON/YAML/TOML 格式,渲染成图片
- 📨 render-forward 指令:将合并转发消息渲染成精美的图片
- 🎨 双渲染引擎:支持 Typst(推荐)和 Markdown 两种渲染模式
- 🌈 代码语法高亮:JSON/YAML/TOML 自动语法着色
- 🧵 嵌套转发支持:智能处理多层嵌套的合并转发消息
📦 依赖服务
required:
- markdownToImage # koishi-plugin-markdown-to-image-service
- toImageService # koishi-plugin-to-image-service
- node # koishi-plugin-w-node
- puppeteer # koishi-plugin-puppeteer可选依赖(推荐安装以获得最佳 Typst 渲染效果):
@myriaddreamin/typst-ts-node-compiler>= 0.7.0-rc2
📋 package.json 依赖详解
以下是本插件的依赖配置及其用途说明:
{
// === peerDependencies: 宿主环境必须提供的依赖 ===
// 这些依赖由 Koishi 主程序或其他插件提供,插件不会自己安装
"peerDependencies": {
// Typst 编译器 - 将 Typst 源码编译为 SVG/PDF
// 用于 dump 指令的 Typst 渲染模式,实现精美排版和代码语法高亮
"@myriaddreamin/typst-ts-node-compiler": ">=0.7.0-rc2",
// Koishi 核心框架 - 插件运行的基础环境
"koishi": "^4.18.7",
// 图片服务 - 提供 SVG → PNG 转换(resvg)和字体管理
// Typst 编译输出 SVG,需要此服务转换为最终的 PNG 图片
"koishi-plugin-to-image-service": ">=0.1.0",
// Node.js 模块加载器 - 动态加载 npm 包
// 用于运行时安全加载 @myriaddreamin/typst-ts-node-compiler
"koishi-plugin-w-node": ">=1.0.0"
},
// === peerDependenciesMeta: peerDependencies 的元数据 ===
"peerDependenciesMeta": {
// Typst 编译器标记为可选
// 如果用户只使用 Markdown 渲染模式,可以不安装此依赖
"@myriaddreamin/typst-ts-node-compiler": {
"optional": true
}
},
// === dependencies: 插件自带的运行时依赖 ===
// 这些依赖会随插件一起安装到 node_modules
"dependencies": {
// TOML 解析器 - 将消息对象序列化为 TOML 格式
// 支持 dump-toml 指令输出 TOML 格式的消息数据
"@iarna/toml": "^2.2.5",
// YAML 解析/序列化库 - 将消息对象序列化为 YAML 格式
// 支持 dump-yaml 指令输出 YAML 格式的消息数据
"js-yaml": "^4.1.1",
// Markdown 转图片服务 - 将 Markdown 渲染为图片
// 作为 Typst 渲染的备选方案,适合简单快速的场景
"koishi-plugin-markdown-to-image-service": "^1.3.6"
},
// === devDependencies: 仅开发时需要的依赖 ===
// 发布后不会包含在 npm 包中
"devDependencies": {
// Typst 编译器(开发版本)- 用于本地开发测试
"@myriaddreamin/typst-ts-node-compiler": "^0.7.0-rc2",
// js-yaml 的 TypeScript 类型定义
// 提供 IDE 智能提示和类型检查
"@types/js-yaml": "^4.0.9",
// 以下两个服务的开发版本,用于本地测试
"koishi-plugin-to-image-service": "^0.1.5",
"koishi-plugin-w-node": "^1.0.1"
}
}依赖关系图
┌─────────────────────────────────────────────────────────┐
│ dump 指令渲染流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ 消息对象 ──┬──▶ JSON (内置) │
│ ├──▶ YAML (js-yaml) │
│ └──▶ TOML (@iarna/toml) │
│ │ │
│ ▼ │
│ ┌─────────────┴─────────────┐ │
│ │ │ │
│ [Typst 模式] [Markdown 模式] │
│ │ │ │
│ typst-ts-node-compiler markdown-to-image-service │
│ (via w-node 动态加载) │ │
│ │ │ │
│ ▼ │ │
│ SVG 输出 │ │
│ │ │ │
│ to-image-service │ │
│ (resvg: SVG → PNG) │ │
│ │ │ │
│ └───────────┬───────────────┘ │
│ ▼ │
│ PNG 图片 │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ render-forward 指令渲染流程 │
├─────────────────────────────────────────────────────────┤
│ │
│ 合并转发消息 ──▶ HTML 生成 ──▶ Puppeteer 截图 ──▶ PNG │
│ │
└─────────────────────────────────────────────────────────┘🚀 使用方法
dump 指令
回复一条消息并发送指令:
dump-json # 渲染为 JSON 格式图片
dump-yaml # 渲染为 YAML 格式图片
dump-toml # 渲染为 TOML 格式图片可用选项:
-m, --mode <typst|markdown>- 选择渲染引擎-r, --reply <forward|image>- 回复模式(合并转发/仅图片)-s, --self- 解析当前消息而非被引用的消息
效果预览:

render-forward 指令
回复一条合并转发消息并发送:
render-forward # 渲染合并转发为图片可用选项:
-i, --index <0|1>- 样式选择(0=Source Han Serif 毛玻璃风格, 1=LXGW WenKai 简约风格)
效果预览:
| Source Han Serif 风格 (index=0) | LXGW WenKai 风格 (index=1) |
|:---:|:---:|
|
|
|
🔧 技术实现细节
🎨 代码语法高亮
Typst 渲染引擎
Typst 内置了对多种编程语言的语法高亮支持。本插件使用 Fenced Code Block 语法来触发高亮:
` ` `json
{"key": "value", "count": 42}
` ` `⚠️ 技术要点:Typst 的
#raw(variable, lang: "json")函数对变量内容不会触发语法高亮,只有直接写在源码中的 Fenced Code Block 才会启用高亮。因此本插件将数据直接嵌入 Typst 源码中。
resvg 兼容性修复
Typst 生成的 SVG 使用了 CSS 变量来设置字形颜色:
.outline_glyph path { fill: var(--glyph_fill); }然而 resvg 不支持 CSS 变量,这会导致所有文字变成默认颜色。本插件通过 fixSvgForResvg() 函数在 SVG 转 PNG 之前移除这些 CSS 变量规则,让颜色从父元素的 fill 属性正确继承:
private fixSvgForResvg(svg: string): string {
// 移除 CSS 变量规则,让颜色从父元素 <g fill="#color"> 继承
return svg.replace(
/\.outline_glyph[^}]*fill:\s*var\(--glyph_fill\)[^}]*}/g,
''
)
}Markdown 渲染引擎
Markdown 渲染使用 koishi-plugin-markdown-to-image-service,通过标准的 Markdown Fenced Code Block 实现语法高亮:
```json
{"key": "value"}
```📨 合并转发渲染的排版设计
Puppeteer 页面截图
合并转发渲染使用 Puppeteer 将 HTML 页面渲染为图片。关键的排版技巧:
1. 自适应高度
使用 height: auto 的卡片容器,让内容自然撑开高度:
.card {
width: 920px;
height: auto; /* 内容自适应 */
border-radius: 32px;
}2. 双风格系统
- Source Han Serif 风格:毛玻璃效果,使用
backdrop-filter: blur()实现 - LXGW WenKai 风格:简约扁平设计,清晰易读
/* 毛玻璃效果 */
.card {
background: rgba(255,255,255,.13);
backdrop-filter: blur(13px) saturate(130%);
box-shadow: 0 16px 48px rgba(0,0,0,.3);
}3. 头像与布局
每条消息使用 Flex 布局,头像固定尺寸,内容区自适应:
.message-item {
display: flex;
gap: 14px;
}
.message-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
flex-shrink: 0; /* 不压缩 */
}
.message-main {
flex: 1;
min-width: 0; /* 防止内容溢出 */
}🧵 嵌套合并转发的处理
OneBot 的合并转发消息可能包含多层嵌套。本插件通过递归渲染和深度限制来优雅处理:
递归解析架构
function parseMessageElement(
element: MessageElement,
currentDepth: number, // 当前嵌套深度
maxDepth: number // 最大允许深度(可配置,默认 3)
): string {
if (element.type === 'forward') {
// 达到最大深度时折叠显示
if (currentDepth >= maxDepth) {
return `<span class="collapsed">[合并转发: ${count}条消息,已达最大嵌套深度]</span>`
}
// 递归渲染嵌套内容
return generateNestedForwardHtml(element.data.content, currentDepth + 1, maxDepth)
}
// ... 其他消息类型处理
}视觉层级区分
嵌套的合并转发使用不同的视觉样式来区分层级:
.nested-forward {
margin: 12px 0;
border-radius: 12px;
border: 1px solid rgba(255,255,255,.6);
background: rgba(255,255,255,.2);
}
.nested-forward[data-depth="2"] {
/* 更深层级可以有不同样式 */
}深度标识
每个嵌套层级都会显示深度信息,帮助用户理解消息结构:
📨 嵌套合并转发 (5条消息, 深度:2)⚙️ 配置项
🔤 字体配置
本插件需要配置字体路径才能正常渲染。你可以:
- 下载预置字体:前往 Gitee Releases - fonts 下载字体文件
- 使用自己喜欢的字体:支持
.ttf和.otf格式
下载后将字体文件放到服务器上,然后在配置中填入绝对路径即可。
需要配置的字体路径(共 3 个):
| 配置项 | 用途 | 推荐字体 |
|--------|------|----------|
| dumpTypstFontPath | dump 指令 (Typst 渲染) | LXGW WenKai Mono |
| renderForwardSourceFontPath | render-forward Source 风格 | Source Han Serif SC |
| renderForwardLxgwFontPath | render-forward LXGW 风格 | LXGW WenKai Mono |
dump 指令配置
| 配置项 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| dumpRenderMode | 'typst' \| 'markdown' | 'typst' | 默认渲染引擎 |
| dumpMessageMode | 'forward' \| 'image' | 'forward' | 回复模式 |
| dumpTypstRenderScale | number | 2.33 | Typst 渲染缩放倍率 |
| dumpTypstPageBgColor | string | '#f9efe2' | 页面背景色 |
| dumpTypstCodeBlockFillColor | string | '#ffffff' | 代码块背景色 |
render-forward 配置
| 配置项 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| maxForwardNestDepth | number | 3 | 最大嵌套深度 |
| renderForwardDefaultStyle | 'source' \| 'lxgw' | 'source' | 默认渲染风格 |
| renderForwardSourceFontPath | string | - | Source 风格字体路径 |
| renderForwardLxgwFontPath | string | - | LXGW 风格字体路径 |
| renderForwardMaxImageSize | number | 50 | 图片最大尺寸 (px) |
