用 PptxGenJS 从零构建专业 PPTX:Onyx PPTX Skill 实战指南
2026/9/10 14:44:59 网站建设 项目流程

用 PptxGenJS 从零构建专业 PPTX:Onyx PPTX Skill 实战指南

【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer

导读:本文是 danswer 仓库 中 PPTX 生成技能的底层引擎教程,围绕 PptxGenJS 这一 JavaScript 库,系统讲解如何通过代码从零创建幻灯片——涵盖版式尺寸、文本排版、形状、图片、图标、表格、图表、母版等全部核心能力,并完整收录本技能在长期实践中沉淀的"坑点清单"(文件损坏、视觉错乱等高频故障)。读完本文,你将能独立编写出可运行、可复用、能通过 lint.py 布局质检的演示文稿脚本,并理解图标渲染(icon.js)与图表美化(chart.py)等配套工具的底层原理。


一、定位与前提:本教程在技能体系中的角色

在 Onyx 的 PPTX Skill 中,创建演示文稿有两条路径:

  • 默认路径:使用 components.md 描述的组件库(components.js)——每个组件是经过测试的版式函数,固定 0.5" 边距、内置字体规范与防溢出保护;
  • 原生路径:当组件库无法覆盖某个版式时,退回本文档讲解的PptxGenJS 原生 API手工排布形状与文本。

从 SKILL.md 可以看到,技能约定所有命令都在会话工作区执行(不要cd进技能目录),技能脚本统一以.opencode/skills/pptx/为前缀,生成文件一律写入outputs/。在仓库中,这些脚本的物理位置是backend/onyx/skills/builtin/pptx/。依赖方面,pptxgenjs已作为全局 npm 包预装进沙箱镜像,无需(也不应)自行安装——components.js 中的加载逻辑会从全局 npm 根目录解析它。

构建顺序(硬性要求):必须先产出一份"文本完整可用的 PPTX"落盘到outputs/,再做图表、图标等美化增强,最后运行lint.py做 QA。任何一步时间不够,都应停止增强、保住已保存的成品。


二、环境搭建与基础结构

安装依赖并创建第一个演示文稿:

npm install -g pptxgenjs

基础代码骨架:

const pptxgen = require("pptxgenjs"); let pres = new pptxgen(); pres.layout = 'LAYOUT_16x9'; // 或 'LAYOUT_16x10'、'LAYOUT_4x3'、'LAYOUT_WIDE' pres.author = 'Your Name'; pres.title = 'Presentation Title'; let slide = pres.addSlide(); slide.addText("Hello World!", { x: 0.5, y: 0.5, fontSize: 36, color: "363636" }); pres.writeFile({ fileName: "Presentation.pptx" });

要点说明:

  • pres.layout在创建任何幻灯片之前设置,决定整份画布的物理尺寸(见下节);
  • pres.author/pres.title写入文档元数据属性;
  • pres.writeFile({ fileName })支持同步返回 Promise,也可用await等待写出完成;
  • 在技能体系内,输出文件务必写到outputs/<名称>.pptx,例如outputs/deck.pptx

关于实例复用:每份演示文稿必须使用全新的pptxgen()实例,绝不要跨文件复用同一实例(详见「常见陷阱」第 6 条)。


三、版式尺寸(Layout Dimensions)

坐标系统以英寸为单位,四种内置版式如下(LAYOUT_WIDE即 16:9 加宽版):

版式常量宽 × 高(英寸)适用场景
LAYOUT_16x910" × 5.625"默认,标准 16:9 投屏
LAYOUT_16x1010" × 6.25"较矮的宽屏
LAYOUT_4x310" × 7.5"传统 4:3 投影仪
LAYOUT_WIDE13.3" × 7.5"超宽屏,内容密度更高

设计建议(来自 SKILL.md 的间距规范):

  • 最小边距 0.5";
  • 内容块之间留 0.3–0.5" 间隙;
  • 10" × 5.625" 画布上,半页图表约 4.5 × 3.2",三分之二宽约 6 × 3.5"(见 charts.md)。

四、文本与排版(Text & Formatting)

4.1 基础文本

slide.addText("Simple Text", { x: 1, y: 1, w: 8, h: 2, fontSize: 24, fontFace: "Arial", color: "363636", bold: true, align: "center", valign: "middle" });

常用属性:x/y/w/h(英寸)、fontSizefontFacecolor(6 位十六进制、不带#)、boldalign("left"/"center"/"right")、valign("top"/"middle"/"bottom")。

4.2 字符间距

// ✅ 用 charSpacing,letterSpacing 会被静默忽略 slide.addText("SPACED TEXT", { x: 1, y: 1, w: 8, h: 1, charSpacing: 6 });

这是本技能实测得出的结论:letterSpacing参数虽然不报错但不生效,字距必须使用charSpacing

4.3 富文本数组(Rich Text)

slide.addText([ { text: "Bold ", options: { bold: true } }, { text: "Italic ", options: { italic: true } } ], { x: 1, y: 3, w: 8, h: 1 });

数组每个元素是{ text, options }options可携带任意单段文本属性,实现同一文本框内不同样式混排。

4.4 多行文本(必须 breakLine)

slide.addText([ { text: "Line 1", options: { breakLine: true } }, { text: "Line 2", options: { breakLine: true } }, { text: "Line 3" } // 最后一项无需 breakLine ], { x: 0.5, y: 0.5, w: 8, h: 2 });

数组项之间若想换行,必须在除最后一项外的每一项上加breakLine: true,否则多段文本会被拼在同一行内。

4.5 文本框内边距

slide.addText("Title", { x: 0.5, y: 0.3, w: 9, h: 0.6, margin: 0 // 与形状/图标对齐时务必设为 0 });

关键提示:文本框默认有内部边距(padding)。当需要文本与同一 x 坐标上的形状、线条或图标精确对齐时,必须显式设置margin: 0。这也是 SKILL.md 中「常见错误」列表明确提醒的一条——"不要忘记文本框 padding,对齐线条或形状与文字边缘时设置margin: 0,或为形状补偿这段偏移"。

4.6 字体规范

从零构建时,SKILL.md 只允许使用沙箱中已安装的字体(Inter、Montserrat、Lato、EB Garamond、Fira Code,以及 Calibri、Cambria、Arial、Times New Roman 等度量兼容替代字体)——其他字体名会被静默回退导致渲染错乱。同时给出了字号层级:幻灯片标题 36–44pt 加粗、章节标题 20–24pt 加粗、正文 14–16pt、注释 10–12pt。这些字体白名单在 lint.py 的KNOWN_FONTS集合中有对应实现,lint 时会逐一核对文本运行中的字体名并给出FONT警告。


五、列表与项目符号(Lists & Bullets)

// ✅ 正确:多项目符号 slide.addText([ { text: "First item", options: { bullet: true, breakLine: true } }, { text: "Second item", options: { bullet: true, breakLine: true } }, { text: "Third item", options: { bullet: true } } ], { x: 0.5, y: 0.5, w: 8, h: 3 }); // ❌ 错误:永远不要用 unicode 圆点符号 slide.addText("• First item", { ... }); // 会产生双重项目符号 // 子项与编号列表 { text: "Sub-item", options: { bullet: true, indentLevel: 1 } } { text: "First", options: { bullet: { type: "number" }, breakLine: true } }

规则总结:

  • 项目符号统一使用bullet: true禁止手写 "•" 等 Unicode 符号——PptxGenJS 会叠加生成自己的符号,造成"双圆点";
  • 子级缩进用indentLevel: 1(或更大层级);
  • 编号列表用bullet: { type: "number" }
  • 配合breakLine: true使用(见上节)。

六、形状(Shapes)

6.1 基础形状

slide.addShape(pres.shapes.RECTANGLE, { x: 0.5, y: 0.8, w: 1.5, h: 3.0, fill: { color: "FF0000" }, line: { color: "000000", width: 2 } }); slide.addShape(pres.shapes.OVAL, { x: 4, y: 1, w: 2, h: 2, fill: { color: "0000FF" } }); slide.addShape(pres.shapes.LINE, { x: 1, y: 3, w: 5, h: 0, line: { color: "FF0000", width: 3, dashType: "dash" } });

pres.shapes上暴露的形状类型至少包括:RECTANGLEOVALLINEROUNDED_RECTANGLE(完整列表见文末「快速参考」)。

6.2 透明与圆角

// 填充透明(0-100) slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 3, h: 2, fill: { color: "0088CC", transparency: 50 } }); // 圆角矩形:rectRadius 只对 ROUNDED_RECTANGLE 生效 // ⚠️ 不要与矩形装饰条搭配使用——矩形条无法覆盖圆角 slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: 1, y: 1, w: 3, h: 2, fill: { color: "FFFFFF" }, rectRadius: 0.1 });

rectRadius单位为英寸,仅对ROUNDED_RECTANGLE生效,对普通RECTANGLE无效。若在圆角矩形左侧叠加一条细矩形作强调色带,色带的直角会盖不住圆角轮廓——此时应改用普通RECTANGLE(详见「常见陷阱」第 8 条)。

6.3 阴影

slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 3, h: 2, fill: { color: "FFFFFF" }, shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.15 } });

阴影选项完整参数表(实测自本技能文档):

属性类型取值范围说明
typestring"outer""inner"外阴影 / 内阴影
colorstring6 位十六进制(如"000000"不带#前缀,也不接受 8 位 hex,否则损坏文件
blurnumber0-100 pt模糊半径
offsetnumber0-200 pt必须非负——负值会损坏文件
anglenumber0-359 度阴影投射方向(135 = 右下,270 = 向上)
opacitynumber0.0-1.0透明度的唯一正确表达方式

向上投影(例如页脚横条上方)应使用angle: 270+ 正offset严禁负 offset。

渐变填充:PptxGenJS 原生不支持渐变,需要渐变背景时请用渐变图片代替。


七、图片(Images)

7.1 三种图片来源

// 从文件路径 slide.addImage({ path: "images/chart.png", x: 1, y: 1, w: 5, h: 3 }); // 从 URL slide.addImage({ path: "https://example.com/image.jpg", x: 1, y: 1, w: 5, h: 3 }); // 从 base64(更快,无文件 I/O) slide.addImage({ data: "image/png;base64,iVBORw0KGgo...", x: 1, y: 1, w: 5, h: 3 });

7.2 图片选项

slide.addImage({ path: "image.png", x: 1, y: 1, w: 5, h: 3, rotate: 45, // 0-359 度 rounding: true, // 圆形裁剪 transparency: 50, // 0-100 flipH: true, // 水平翻转 flipV: false, // 垂直翻转 altText: "Description", // 无障碍描述 hyperlink: { url: "https://example.com" } });

7.3 三种尺寸模式(sizing)

// Contain - 等比缩放完整放入,可能留白 { sizing: { type: 'contain', w: 4, h: 3 } } // Cover - 等比缩放填满区域(可能裁切) { sizing: { type: 'cover', w: 4, h: 3 } } // Crop - 裁切特定区域 { sizing: { type: 'crop', x: 0.5, y: 0.5, w: 2, h: 2 } }

7.4 按宽高比计算尺寸(核心技巧)

const origWidth = 1978, origHeight = 923, maxHeight = 3.0; const calcWidth = maxHeight * (origWidth / origHeight); const centerX = (10 - calcWidth) / 2; // 10 是 LAYOUT_16x9 的宽度 slide.addImage({ path: "image.png", x: centerX, y: 1.2, w: calcWidth, h: maxHeight });

先用原图宽高比推算目标宽度,再以(画布宽 - 图片宽) / 2水平居中,即可保证图片不变形且居中。

7.5 支持格式

  • 标准:PNG、JPG、GIF(动图在 Microsoft 365 中可播放);
  • SVG:可在新版 PowerPoint / Microsoft 365 中正常显示。

八、图标(Icons)

技能内置了图标渲染脚本 icon.js,把 lucide / tabler 图标集的 SVG 栅格化成可着色的 PNG。依赖(lucide-static@tabler/iconssharp)已预装进沙箱镜像,无需任何安装步骤。

8.1 渲染一个图标 PNG

node .opencode/skills/pptx/scripts/icon.js circle-check --color FFFFFF --size 512 -o outputs/icons/check.png

参数说明:

参数说明
<icon-name>kebab-case 图标文件名(如circle-checktrending-upshield-check
--colorhex 颜色,#可省略(默认黑色)。注意:pptxgenjs 中使用的颜色仍须省略#
--size栅格化分辨率 px(默认 512——在任何幻灯片尺寸下都足够清晰;显示大小由放置时的w/h英寸决定)
-o输出路径(默认outputs/icons/<icon-name>.png
--set lucide\|tabler限定只从一个图标集查找

使用原则:每个(图标, 颜色)组合只渲染一次outputs/icons/,之后在多个幻灯片间复用同一个 PNG。一份演示文稿只使用一个图标集(默认优先 lucide)——混用两套图标会因描边粗细与转角风格不同破坏视觉一致性。

8.2 查找图标名(先查后画)

图标名是主要故障点,不确定时先搜索再渲染

node .opencode/skills/pptx/scripts/icon.js --list "shield" # 两个图标集一起搜 node .opencode/skills/pptx/scripts/icon.js --list "chart" --set lucide # 限定某一图标集

两个图标集:lucide(约 2,000 个,简洁线性风格,作为默认)与tabler(约 6,000 个,线性 + 填充两种,lucide 没有对应概念时使用)。

从 icon.js 源码看实现细节:

  • 渲染路径先定位包目录(lucide-static/icons@tabler/icons/icons/outlinefilled),再用sharp渲染。两个包导出的 SVG 原始尺寸均为 24×24,脚本通过density = (72 * size) / 24提高栅格化密度,保证任意目标尺寸下都是矢量级清晰而非从 24px 放大(icon.js);
  • --color通过把 SVG 中的currentColor替换为实际 hex 实现着色(icon.js),支持 3 位或 6 位 hex;
  • --list子命令在未命中时会基于编辑距离 + 子串匹配给出最多 8 个相近名称建议(icon.js);
  • --size合法范围 16–2048 px,超出会直接报错退出(icon.js)。

8.3 常用图标速查(lucide)

语义图标语义图标
勾选 / 成功circle-check目标 / 靶心target
增长 / 上升trending-up风险 / 警告triangle-alert
下降 / 减少trending-down全球 / 市场globe
团队 / 人群users指标 / 柱状图chart-column
个人 / 客户user数据 / 存储database
设置 / 流程settings文档 / 报告file-text
安全 / 防护shield邮件 / 联系mail
时间 / 速度clock创意 / 洞察lightbulb
日程 / 日期calendar发布 / 启动rocket
成本 / 营收dollar-sign能量 / 性能zap
奖项 / 质量award搜索 / 发现search

8.4 放到幻灯片上

// 彩色圆底 + 图标(图标颜色要与圆底形成对比) slide.addShape(pres.shapes.OVAL, { x: 0.5, y: 1.0, w: 0.6, h: 0.6, fill: { color: "1E2761" } }); slide.addImage({ path: "outputs/icons/check.png", x: 0.62, y: 1.12, w: 0.36, h: 0.36 });

这是 SKILL.md 推荐的经典"图标 + 彩色圆底"版式(图标置于圆中时渲染与圆底对比强烈的颜色),常用于图标行、特性列表等版式。


九、幻灯片背景(Slide Backgrounds)

// 纯色 slide.background = { color: "F1F1F1" }; // 带透明度的颜色 slide.background = { color: "FF3399", transparency: 50 }; // URL 图片 slide.background = { path: "https://example.com/bg.jpg" }; // base64 图片 slide.background = { data: "image/png;base64,iVBORw0KGgo..." };

SKILL.md 建议采用"三明治"明暗结构:标题页与结论页用深色背景、内容页用浅色,或整份统一深色以营造高级感。


十、表格(Tables)

slide.addTable([ ["Header 1", "Header 2"], ["Cell 1", "Cell 2"] ], { x: 1, y: 1, w: 8, h: 2, border: { pt: 1, color: "999999" }, fill: { color: "F1F1F1" } }); // 进阶:合并单元格 let tableData = [ [{ text: "Header", options: { fill: { color: "6699CC" }, color: "FFFFFF", bold: true } }, "Cell"], [{ text: "Merged", options: { colspan: 2 } }] ]; slide.addTable(tableData, { x: 1, y: 3.5, w: 8, colW: [4, 4] });

要点:

  • 表格数据是二维数组,单元格既可以是字符串,也可以是{ text, options }对象以单独控制填充色、文字色、加粗等;
  • colspan实现横向合并;colW按列指定宽度数组;
  • 表格样式规范可参考 components.md 中tableSlide组件:加粗表头、细线行分隔(不推荐斑马纹),约 8 行 × 5 列上限。

十一、图表(Charts)

11.1 原生图表

// 柱状图 slide.addChart(pres.charts.BAR, [{ name: "Sales", labels: ["Q1", "Q2", "Q3", "Q4"], values: [4500, 5500, 6200, 7100] }], { x: 0.5, y: 0.6, w: 6, h: 3, barDir: 'col', showTitle: true, title: 'Quarterly Sales' }); // 折线图 slide.addChart(pres.charts.LINE, [{ name: "Temp", labels: ["Jan", "Feb", "Mar"], values: [32, 35, 42] }], { x: 0.5, y: 4, w: 6, h: 3, lineSize: 3, lineSmooth: true }); // 饼图 slide.addChart(pres.charts.PIE, [{ name: "Share", labels: ["A", "B", "Other"], values: [35, 45, 20] }], { x: 7, y: 1, w: 5, h: 4, showPercent: true });

注意数据真实性红线:无论是原生图表还是 PNG 图表,charts.md 明确要求只绘制真实数据——数据必须来自用户消息、附件、工作区文件或公司检索结果,绝不虚构数字填图。只有一个数字时用"大数字 + 标签"的统计调用卡(stat callout)代替单柱图表。

11.2 让图表更好看(推荐样式集)

原生默认样式过时,应用以下选项获得现代、干净的外观:

slide.addChart(pres.charts.BAR, chartData, { x: 0.5, y: 1, w: 9, h: 4, barDir: "col", // 自定义配色(贴合演示文稿主色板) chartColors: ["0D9488", "14B8A6", "5EEAD4"], // 干净背景 chartArea: { fill: { color: "FFFFFF" }, roundedCorners: true }, // 柔和的轴标签 catAxisLabelColor: "64748B", valAxisLabelColor: "64748B", // 极淡网格线(仅数值轴) valGridLine: { color: "E2E8F0", size: 0.5 }, catGridLine: { style: "none" }, // 柱顶数据标签 showValue: true, dataLabelPosition: "outEnd", dataLabelColor: "1E293B", // 单序列隐藏图例 showLegend: false, });

关键样式选项速查

  • chartColors: [...]— 序列/扇区的 hex 颜色;
  • chartArea: { fill, border, roundedCorners }— 图表背景;
  • catGridLine/valGridLine: { color, style, size }— 网格线(style: "none"隐藏);
  • lineSmooth: true— 折线平滑曲线;
  • legendPos: "r"— 图例位置:"b"、"t"、"l"、"r"、"tr"。

11.3 技能内的推荐姿势:PNG 图表

需要注意,charts.md 给出的默认推荐不是原生addChart,而是用 chart.py 以 matplotlib 渲染成 PNG 再addImage放置——因为原生图表样式控制力弱,只有用户明确要求可编辑图表时才用addChart

chart.py 的核心用法(先定英寸区域,再按同一尺寸放置 PNG):

import sys sys.path.insert(0, ".opencode/skills/pptx/scripts") import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt from chart import deck_style, save_for_slide DECK_PALETTE = ["1E2761", "CADCFC", "F96167"] # 演示文稿主色板,主色在前 with deck_style(palette=DECK_PALETTE, font="Montserrat"): fig, ax = plt.subplots(layout="constrained") ax.bar(["Q1", "Q2", "Q3", "Q4"], [4500, 5500, 6200, 7100]) ax.set_title("Quarterly Sales") save_for_slide(fig, "outputs/chart-sales.png", width_in=6, height_in=3.5)
// pptxgenjs 放置(尺寸与 save_for_slide 的 width_in/height_in 完全一致) slide.addImage({ path: "outputs/chart-sales.png", x: 0.5, y: 1.2, w: 6, h: 3.5 });

从源码看,chart.py 的deck_style会一次性配置axes.prop_cycle(按主色板循环上色)、去掉上/右脊柱、仅保留 y 轴网格、统一字号与legend.frameon: False等(chart.py);save_for_slide200 DPI(2 倍分辨率)导出(chart.py),保证缩放后依然锐利。


十二、幻灯片母版(Slide Masters)

pres.defineSlideMaster({ title: 'TITLE_SLIDE', background: { color: '283A5E' }, objects: [{ placeholder: { options: { name: 'title', type: 'title', x: 1, y: 2, w: 8, h: 2 } } }] }); let titleSlide = pres.addSlide({ masterName: "TITLE_SLIDE" }); titleSlide.addText("My Title", { placeholder: "title" });

母版机制把版式(背景、占位符)与内容解耦:defineSlideMaster定义具名版式,addSlide({ masterName })应用版式,placeholder: "title"把文本填充进对应占位符。适合需要在多张幻灯片间复用的统一版式(标题页、章节页、结尾页)。


十三、常见陷阱(Common Pitfalls)

以下问题会导致文件损坏、视觉错乱或输出无效,务必规避。

1. 颜色永远不要带#前缀——会导致文件损坏

color: "FF0000" // ✅ 正确 color: "#FF0000" // ❌ 错误

2. 不要把透明度编码进 hex 颜色串——8 位 hex 会损坏文件,请用opacity属性

shadow: { type: "outer", blur: 6, offset: 2, color: "00000020" } // ❌ 损坏文件 shadow: { type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.12 } // ✅ 正确

3. 用bullet: true——绝不用 "•" 等 Unicode 符号(会产生双项目符号)。

4. 数组项或文本运行(run)之间用breakLine: true换行,否则会被拼在同一行。

5. 项目符号列表避免lineSpacing——会造成段落间距过大;改用paraSpaceAfter

6. 每份演示文稿使用全新实例——不要复用pptxgen()对象。

7. 绝不在多次调用间复用选项对象——PptxGenJS 会原地修改对象(例如把阴影值就地转换为 EMU 单位)。多个形状共享同一对象时,第二次调用拿到的已是转换后的值,导致第二个形状损坏:

const shadow = { type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.15 }; slide.addShape(pres.shapes.RECTANGLE, { shadow, ... }); // ❌ 第二次调用拿到已被转换的值 slide.addShape(pres.shapes.RECTANGLE, { shadow, ... }); const makeShadow = () => ({ type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.15 }); slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow(), ... }); // ✅ 每次调用生成新对象 slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow(), ... });

8. 不要用ROUNDED_RECTANGLE搭配矩形强调条——矩形覆盖不了圆角,改用RECTANGLE

// ❌ 错误:强调条盖不住圆角 slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: 1, y: 1, w: 3, h: 1.5, fill: { color: "FFFFFF" } }); slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 0.08, h: 1.5, fill: { color: "0891B2" } }); // ✅ 正确:全部用 RECTANGLE 保证对齐干净 slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 3, h: 1.5, fill: { color: "FFFFFF" } }); slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 0.08, h: 1.5, fill: { color: "0891B2" } });

十四、质量保障:与 lint.py 协同(QA)

原生的 PptxGenJS 排布自由度大,出错概率也高,因此技能强制在交付前运行确定性布局检查器 lint.py:

python .opencode/skills/pptx/scripts/lint.py outputs/output.pptx
  • 退出码 0 且输出LINT_CLEAN表示无问题;非零表示存在 ERROR 级问题;
  • 每个 ERROR 都必须修复;WARN 逐条评估,除非是刻意的设计重叠;
  • 每修完一批立刻重跑(秒级完成),直至干净再进入渲染阶段。

lint.py 的六类检查与 PptxGenJS 排布直接相关(lint.py):

检查码含义与本文的关联
BOUNDS形状部分/整体超出画布x/y/w/h英寸坐标直接相关
MARGIN文本距画布边缘小于 0.5"(--profile dense放宽到 0.25")呼应 SKILL.md 的 0.5" 最小边距规范
OVERFLOW估计文本高度超出文本框(PIL 字体度量)对应breakLine/fontSize的合理取值
OVERLAP两个文本框架相交,或文本溢出容器对应margin: 0对齐与元素间距
CONTRAST显式文本色与实色背景对比度不足(WCAG 阈值)对应颜色值规范(6 位 hex)
FONT字体不在沙箱已知字体集对应「字体规范」小节的可用字体白名单

lint.py 在测量文本大小时会把字体按 4 倍字号渲染以获得亚像素级精度(MEASURE_SCALE = 4),并通过fc-match解析系统字体文件(lint.py)。内容密集的分析型/咨询型幻灯片(故意收紧边距)可用--profile dense只放宽 MARGIN 告警,错误级检查不变。

lint 通过后,再进入视觉 QA:soffice转 PDF、pdftoppm转逐页 JPEG 交由子代理检查(流程见 SKILL.md 的 "Converting to Images" 与 "QA" 章节)。只有在完成至少一轮"修复 → 复检"循环后才能宣布交付成功。


十五、快速参考(Quick Reference)

  • 形状RECTANGLEOVALLINEROUNDED_RECTANGLE
  • 图表类型BARLINEPIEDOUGHNUTSCATTERBUBBLERADAR
  • 版式LAYOUT_16x9(10"×5.625")、LAYOUT_16x10LAYOUT_4x3LAYOUT_WIDE
  • 对齐:"left"、"center"、"right"
  • 图表数据标签位置:"outEnd"、"inEnd"、"center"
  • 常用配套脚本(均在会话工作区以.opencode/skills/pptx/前缀调用,仓库内物理路径见backend/onyx/skills/builtin/pptx/scripts/):
    • 图标渲染/搜索:scripts/icon.js
    • 布局 lint:scripts/lint.py
    • 图表 PNG 渲染:scripts/chart.py
    • 组件库(默认从零构建路径):scripts/components.js

结语

本文以 pptxgenjs.md 为主线,完整覆盖了 PptxGenJS 从零构建 PPTX 的全部能力:版式常量与坐标体系、富文本与列表、形状与阴影、图片与图标、背景与表格、图表与母版,并逐条收录了"颜色不带#""8 位 hex 损坏文件""选项对象原地修改""圆角矩形不能叠矩形条"等由实战沉淀的坑点。配合 icon.js、chart.py 与 lint.py 的源码级解读,你可以在此基础上写出首轮即通过 lint、视觉整洁、可交付的演示文稿脚本——如需更快的版式组装,请优先参考 components.md 的组件库;处理已有模板则走 editing.md 的模板编辑流程。

【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询