PPTX 创建、编辑与分析
.pptx 文件是一个 XML 文件的 ZIP 归档。根据任务选择方法:
| 任务 | 方法 |
|---|---|
| 创建新演示文稿 | 编写 pptxgenjs 脚本 — 参见下方注意事项 |
| 编辑现有演示文稿,或基于模板创建 | 解压 → 编辑 ppt/slides/slideN.xml → 压缩 |
| 读取内容 | markitdown deck.pptx(每个幻灯片一个块,位于 <!-- Slide number: N --> 标记下);可视化网格:python scripts/thumbnail.py deck.pptx |
脚本
路径相对于此技能目录。其他均为纯 Python、node 或 shell 脚本。
| 脚本 | 功能 |
|---|---|
scripts/thumbnail.py deck.pptx [前缀] | 每张幻灯片的带标签网格,用于选择模板布局。仅适用于 .pptx 文件。传递 prefix — 默认为 thumbnails,会覆盖同一目录中其他演示文稿的网格 |
scripts/add_slide.py unpacked/ slide2.xml [--after slideN.xml] | 复制幻灯片(或 slideLayoutN.xml),并处理所有包簿记操作。也可直接处理 .pptx 文件,需使用 -o out.pptx |
scripts/clean.py unpacked/ | 删除不再被引用的幻灯片、媒体和关联文件。在 <p:sldIdLst> 最终确定后运行 |
scripts/office/validate.py deck.pptx [--original src.pptx] | 进行架构、关系、内容类型、图表和幻灯片检查;每个失败项都会说明修复方法。对于任何基于模板的演示文稿,传递 --original — 它会将架构检查与模板进行基线对比,这样模板自身的 XSD 错误就不会被误认为是你的错误 |
scripts/office/soffice.py --headless --convert-to pdf deck.pptx | LibreOffice 包装器 — 裸 soffice 在此沙盒中会挂起 |
使用 pptxgenjs 创建 — 注意事项
pptxgenjs 已预安装 — 不要先运行 npm install;直接编写脚本并 require('pptxgenjs')。仅当该 require 失败时才:npm install pptxgenjs。模型已了解 API;以下是一些容易踩坑的地方:
- 在添加幻灯片之前设置
pres.layout。 默认画布是LAYOUT_16x9= 10" × 5.625",不是 13.3" 宽。超出边界的坐标会被写入,但不会被裁剪 — 形状只是不在幻灯片上。(LAYOUT_WIDE是 13.3" × 7.5"。) - 十六进制颜色:永远不要
#,永远不要 8 位数字。color: "FF0000"。"#FF0000"和将 Alpha 值嵌入十六进制("00000020")都会损坏文件。如需半透明效果:在填充和图像上使用transparency: 0-100,在阴影上使用opacity: 0.0-1.0— 每个选项在对方属性上会被静默忽略。 - pptxgenjs 会就地修改选项对象(首次使用时将值转换为 EMU)。永远不要在两次
add*调用之间共享同一个shadow/options 对象 — 每次都构建一个新的对象。 - 阴影
offset必须 ≥ 0 — 负偏移会损坏文件。要向上投射阴影,请使用angle: 270配合正偏移。 letterSpacing会被静默忽略 — 实际选项是charSpacing。- 列表: 每个项目上使用
bullet: true,不要使用字面量•(会渲染出双重项目符号)。除最后一个数组项外,每个数组项都设置breakLine: true。使用paraSpaceAfter(而不是lineSpacing)来分隔带项目符号的段落(后者会产生巨大间距)。 - 每个输出文件使用一个
new pptxgen()— 永远不要重复使用同一个实例。 rectRadius仅适用于ROUNDED_RECTANGLE,不适用于RECTANGLE。- 不支持渐变填充 — 请改用渐变图像作为背景。
- 文本框有内置内边距 — 当文本必须与相同 x 坐标的形状、线条或图标对齐时,设置
margin: 0。 - 演讲者备注放到
slide.addNotes("...")中(纯文本,每张幻灯片一次),永远不要放在幻灯片上的文本框里。 - 保持图表的原生性。 对于 PowerPoint 能生成的所有图表类型,使用
addChart()(对于组合图表,传递{type, data, options}数组)。对于库未暴露的 PowerPoint 原生功能(趋势线、误差线),自行计算额外系列或后处理生成的 OOXML — 不要退回到渲染图像。仅当 PowerPoint 没有原生形式的图表类型(桑葚图、网络图、弦图)时,才以图像形式插入。 - 默认图表渲染较简陋 — 没有标题、没有数据标签、调色板过时。设置
showTitle+title、showValue: true+dataLabelPosition、使用调色板的chartColors: [...],并隐藏框架(catAxisLabelColor/valAxisLabelColor、valGridLine: { color, size }、catGridLine: { style: "none" }、对于单个系列设置showLegend: false)。 - 在堆积柱状图或条形图上,
dataLabelPosition必须是ctr、inEnd或inBase。outEnd会损坏文件。 - 使用
secondaryValAxis/secondaryCatAxis的组合系列需要在图表选项中同时提供valAxes和catAxes,每个各两项。 如果不提供,pptxgenjs 会写入它从未声明的轴 ID,PowerPoint 会丢弃该图表并报告文件已损坏。仅提供valAxes是不够的。 - 在
writeFile()之后,运行python scripts/office/validate.py deck.pptx。 它会报告上述两个图表错误以及 PowerPoint 拒绝的幻灯片 XML 缺陷,并为每个问题说明修复方法。在生成器中修复它们,而不是手动编辑打包的 XML。 - 永远不要重新排列
<p:presentation>的子元素。 pptxgenjs 将<p:notesMasterIdLst>写在<p:sldIdLst>之后,并将两个母版指向同一个主题部分。PowerPoint 可以正常读取 — 移动该元素后,同一个演示文稿将无法打开。 - 图标: 将
react-icons渲染为 SVG(ReactDOMServer.renderToStaticMarkup),使用sharp在 ≥256px 下光栅化,并通过addImage({ data: "image/png;base64," + buf.toString("base64") })插入 — 需要image/png;base64,前缀(react-icons、react、react-dom和sharp已预安装 — 仅在 require 失败时才运行npm install react-icons react react-dom sharp)。
编辑现有演示文稿和模板
首先选择布局:python scripts/thumbnail.py template.pptx template-thumbs 会写入每张幻灯片的带标签网格,并打印创建的文件 — template-thumbs.jpg,如果超过 12 张幻灯片,则会拆分为 template-thumbs-N.jpg。始终传递第二个参数,并以演示文稿命名。 默认为 thumbnails,因此同一目录中两个演示文稿的缩略图会静默地互相覆盖对方的网格 — 第一个演示文稿的网格会消失(模板分析 — 可视化 QA 需要 转换为图像 中的全分辨率渲染;它只接受 .pptx,因此请先将 .potx 文件复制为 .pptx 文件名)。与 markitdown 一起使用,将每个内容部分映射到模板幻灯片上,并变化布局 — 不要将每个部分都放在同一个标题和项目符号幻灯片上。
python3 -c "import sys,zipfile; zipfile.ZipFile(sys.argv[1]).extractall('unpacked')" deck.pptx
python scripts/add_slide.py unpacked/ slide2.xml --after slide2.xml # 复制幻灯片(或 slideLayoutN.xml);打印新幻灯片的路径
# 重新排序/删除幻灯片 = 编辑 ppt/presentation.xml 中的 <p:sldIdLst>
python scripts/clean.py unpacked/ # 删除后:移除孤立的幻灯片、媒体、关联文件
# 在 ppt/slides/slideN.xml 中编辑幻灯片内容
(cd unpacked && rm -f ../out.pptx && zip -Xr ../out.pptx .) # 在目录内部压缩;先 rm,否则已删除的部分会幸存
python scripts/office/validate.py out.pptx --original deck.pptx
- 在进行所有结构性工作(添加、删除、重新排序)之后,再编辑任何幻灯片的内容。
add_slide.py会逐字复制幻灯片文件,因此在编辑后复制会克隆编辑后的内容;而clean.py会删除<p:sldIdLst>中缺少的任何幻灯片,包括你刚写入的一张。 - 永远不要手动复制幻灯片文件 —
add_slide.py会执行新幻灯片所需的所有注册,并报告它创建的内容(Created ppt/slides/slide17.xml from slide2.xml)。它也可以直接处理文件:add_slide.py deck.pptx slide2.xml -o out.pptx— 传递-o,否则它会就地重写输入演示文稿。 复制的幻灯片仍然引用其来源的图表/SmartArt/嵌入对象部件,而不是克隆它们,因此编辑一张幻灯片的图表会改变另一张的。 - 如果使用
python-pptx,它有三件事不会做:复制幻灯片(其唯一入口点是add_slide(layout))、通过text_frame.text = "..."保留格式(这会将段落折叠为单个未设置格式的运行 — 应改为分配run.text),以及读取大多数模板艺术使用的 SVG/EMF(add_picture会引发UnidentifiedImageError)。 - 旧版
.ppt必须首先转换:python scripts/office/soffice.py --headless --convert-to pptx file.ppt。.potx模板的解压和打包方式相同 — 在输出上保留.potx扩展名。 - 要重复使用模板图标或图像,请复制已包含该内容的幻灯片或布局。
填充模板时:
- 如果编写 XML 转换脚本,请使用
defusedxml.minidom进行解析 — 通过xml.etree.ElementTree往返 OOXML 会重写命名空间前缀并损坏演示文稿。 - 模板槽位 ≠ 源项目。 如果模板显示 4 个团队成员,而你只有 3 个,请删除第 4 个成员的整个组(图像 + 文本框),而不仅仅是其文本 — 然后在 QA 中检查孤立的可视元素。
- 每个列表项一个
<a:p>— 永远不要将项目连接到一个段落中。复制兄弟<a:pPr>以保留间距,并在标题、章节标题和内联标签(Status:、Owner:)的<a:rPr>上设置b="1"。 - 让项目符号从布局继承;仅在需要覆盖时才添加
<a:buChar>、<a:buAutoNum>(编号)或<a:buNone>— 永远不要在文本中使用字面量•。 - 带有前导或尾随空格的文本需要在
<a:t>上设置xml:space="preserve"。
设计想法
不要创建乏味的幻灯片。 白色背景上的纯项目符号不会给任何人留下深刻印象。考虑此列表中的每个幻灯片的想法。
开始之前
- 选择大胆、内容相关的调色板:调色板应针对此主题进行设计。如果将你的颜色替换到完全不同的演示文稿中仍然“可行”,则说明你没有做出足够具体的选择。
- 主次分明:一种颜色应占主导地位(60-70% 的视觉重量),配以 1-2 种支撑色调和一种锐利的强调色。永远不要给所有颜色同等的权重。
- 暗/亮对比:标题和结论幻灯片使用深色背景,内容幻灯片使用浅色(“三明治”结构)。或者全部使用深色以获得高级感。
- 确定视觉主题:选择 ONE 个独特的元素并重复它 — 圆角图像框、彩色圆圈中的图标。在每张幻灯片上贯穿使用。不要使用色条或强调条纹作为你的主题(参见避免列表)。
调色板
选择与你的主题匹配的颜色 — 不要默认使用通用的蓝色。使用以下调色板作为灵感:
| 主题 | 主色 | 辅助色 | 强调色 |
|---|---|---|---|
| 午夜执行 | 1E2761(海军蓝) | CADCFC(冰蓝) | FFFFFF(白色) |
| 森林与苔藓 | 2C5F2D(森林绿) | 97BC62(苔藓绿) | F5F5F5(奶油色) |
| 珊瑚能量 | F96167(珊瑚红) | F9E795(金色) | 2F3C7E(海军蓝) |
| 暖陶土 | B85042(陶土色) | E7E8D1(沙色) | A7BEAE(鼠尾草绿) |
| 海洋渐变 | 065A82(深蓝) | 1C7293(蓝绿色) | 21295C(午夜蓝) |
| 炭灰极简 | 36454F(炭灰色) | F2F2F2(米白色) | 212121(黑色) |
| 蓝绿色信任 | 028090(蓝绿色) | 00A896(海泡沫绿) | 02C39A(薄荷绿) |
| 浆果与奶油 | 6D2E46(浆果色) | A26769(灰玫瑰色) | ECE2D0(奶油色) |
| 鼠尾草宁静 | 84B59F(鼠尾草绿) | 69A297(桉树绿) | 50808E(石板蓝) |
| 樱桃大胆 | 990011(樱桃红) | FCF6F5(米白色) | 2F3C7E(海军蓝) |
对于每张幻灯片
每张幻灯片都需要一个视觉元素 — 图像、图表、图标或形状。纯文本幻灯片容易被遗忘。
布局选项:
- 两列(左文右图)
- 图标 + 文本行(彩色圆圈中的图标、粗体标题、下方描述)
- 2x2 或 2x3 网格(一侧是图像,另一侧是内容块网格)
- 半出血图像(全左或全右侧)搭配内容叠加
数据显示:
- 大号数据标注(大号数字 60-72pt,下方带有小标签)
- 比较列(之前/之后、优点/缺点、并排选项)
- 时间线或流程图(编号步骤、箭头)
视觉润色:
- 章节标题旁边的小彩色圆圈中的图标
- 关键统计信息或标语使用斜体强调文本
排版
你写入 .pptx 的字体名称由用户的 PowerPoint 渲染,而不是此环境。 你的可视化 QA 通过 LibreOffice 渲染,它会替换其没有的字体 — 对于某些字体,替代字体具有不同的宽度,因此你的 QA 预览可能显示真实演示文稿中不存在的文本溢出(或适合)情况。为了使 QA 可靠:
- 安全字体(在 QA 中宽度准确且在 Office 中附带):Arial、Calibri、Cambria、Times New Roman、Courier New、Bookman Old Style、Century Schoolbook。将它们用于正文文本以及任何适合性重要的内容。
- 具有个性且零 QA 风险的标题:将安全列表中的衬线标题字体(Cambria、Bookman Old Style、Century Schoolbook)与安全列表中的无衬线正文字体(Calibri 或 Arial)配对。可以获得视觉对比,而无需放弃可靠的溢出检查。
- 如果用户要求安全列表之外的字体(例如 Georgia 或 Trebuchet MS):在用户要求的地方使用它,但将这些容器的大小设置得额外宽松一些(约 10%),并且不要相信这些元素上的 QA 文本适配 — 该字体的预览是近似的。如果用户没有指定,正文文本优先选择安全列表字体。
- QA 不可靠的字体(替代字体具有不同的宽度 — 溢出检查可能错误):Georgia、Trebuchet MS、Impact、Arial Black、Garamond、Consolas、Palatino Linotype。Calibri Light 的替代因环境而异;视为 QA 不可靠。适用于带有宽松余量的标题/强调文本;不要相信这些字体上的 QA 文本适配。
- 永远不要默认使用 Aptos — Office 2023 年后的默认字体在此没有度量兼容的替代字体,并且在较旧的 Office 安装中缺失,因此它在两端都不可靠。
| 元素 | 字号 |
|---|---|
| 幻灯片标题 | 36-44pt 粗体 |
| 章节标题 | 20-24pt 粗体 |
| 正文文本 | 14-16pt |
| 说明文字 | 10-12pt 柔和 |
…