从 fsys.openXml 0.6.0 起,可不启动 Office/WPS 生成 .pptx。
直接导入 fsys.openXml.pptx.builder 是纯生成路线:不加载 ZIP 读取器、MSXML、.NET 或技能包。ZIP 写入复用公共 zlib.zip.writeData,不为每个部件创建临时文件。主题与备注母版编译内嵌,运行时不需要参考 PPTX。
import fsys.openXml.pptx.builder;
var slides = [{
background = "F4F7FC";
notes = "讲解备注";
transition = {effect="fade";duration=0.7};
shapes = [{
kind="text";name="Title";
x=60;y=60;width=840;height=100;
text="由 aardio 生成的 PPTX";
fontSize=36;bold=true;color="18324F";
animation={effect="fade";trigger="click";duration=0.6};
}];
}];
var path,err = fsys.openXml.pptx.builder.write("/native.pptx",slides);
if(!path) return null,err;
return path;
write(path,slides,options) 返回完整路径,失败 null,err,默认不覆盖。只有明确指定 {overwrite=true} 才覆盖旧目标。fsys.openXml.pptx.write 与技能 writePptx 为便捷转发;需要最小依赖时用上面的直接导入。
表格 margin、valign 的 API 与默认值不变。单元格只通过 a:tcPr 写入四边边距和垂直对齐,内部 a:bodyPr 省略 lIns/rIns/tIns/bIns/anchor,保留 wrap="square" 和 noAutofit。显式写零边距/顶部对齐并不等于省略:WPS 的某些版本会用这些值覆盖 tcPr。
修复仅作用于新生成的表格;普通文本框、形状文字、占位符及备注保持原输出,预检仍只扣一次单元格边距。不要改用空格、段落缩进、缩小字号或在两层重复写边距补偿。旧文稿的编辑保留机制不自动清除这些属性;可重新运行 ~/examples/File/OpenXML/pptx-data.aardio 生成修正版。
用户提供的 WPS Build 12.1.0.16929 对照验证表明:同时省略五属性可恢复 80 个物理格的 9pt 边距及居中,实读字号仍为18pt/15pt。本机 PowerPoint 16 的修前/修后七页同尺寸PNG逐字节相同,实际边距、文本边界、行高与合并格尺寸保持,回存重开也正常。此结论不外推为全部应用版本的字号/排版绝对一致。
kind="chart";chart={type,categories,series} 支持二维柱状/条形/折线/饼图,每图带独立内嵌XLSX,引用与缓存一致。详见 二维原生图表。完整演示:~/examples/File/OpenXML/pptx-charts.aardio。缺值使用null,与0区分;尾部null通过数组元表length保留。check不模拟图表内部标签排版。
表格 merges=[{row,column,rowSpan,colSpan}] 支持横向/纵向/矩形合并,行列从1开始;保留完整物理 rows,覆盖格必须为空。生成与预检共用合并拓扑与总宽高,详见 模板与表格数据。完整演示 ~/examples/File/OpenXML/pptx-data.aardio 还展示 editor 复制/删页与保留格式填值。
支持 options.slideNumber 自动页码、运行 field="slideNumber"、文字/形状/图片 hyperlink、段落 numbering、外阴影 shadow 与圆角矩形 cornerRadius。详见 页码、超链接、编号与外观细节。完整五页交互演示:~/examples/File/OpenXML/pptx-details.aardio。
slide.layout 可为 blank(默认)、title、titleContent、twoContent。标准版式提供真正的标题/正文占位符,并非只有外观的文本框;版式部件、幻灯片及预检共用默认几何。只生成显式提供的 shapes,不自动增加未提供的内容。
placeholder="title":标题(index=0;标题页为 ctrTitle)。placeholder="subtitle":副标题(index=1),用于 title 或显式 blank 页。placeholder="body":正文(默认 index=1);第二栏写 {type="body";index=2}。kind="text" 可做占位符;同页占位符索引必须唯一。省略 x/y/width/height/字号时采用版式默认值,显式字段覆盖。此处 body 是文本占位符,不是通用图表/图片插入容器。animation.byParagraph=true 按非空真实段落展开,软换行不拆段。首次用 trigger/delay;后续用 paragraphTrigger(click/with/after,默认 click)和 paragraphDelay(默认0秒)。paragraph=N 可仅播放某段(从1开始),不能与 byParagraph 同用。不按缩进层级合组,仅支持 entrance/exit 的五种已支持效果。transition.effect="morph" 支持 option=byObject/byWord/byChar(默认 byObject),同时写入 p14/标准淡出回退。相邻页同一对象可用相同的 !! 前缀名称辅助匹配。旧应用的淡出回退不等同 Morph。import fsys.openXml.pptx.builder;
var slides=[{
layout="titleContent";
shapes=[
{name="Title";placeholder="title";text="按段落讲解"},
{name="Body";placeholder="body";text='第一点\r\n第二点\r\n第三点';
animation={effect="fade";byParagraph=true;duration=0.45}}
];
}];
return fsys.openXml.pptx.builder.write("/paragraphs.pptx",slides);
完整五页示例:~/examples/File/OpenXML/pptx-show.aardio。第2页点击三次,第3→4页观察 Morph,第5页两栏自动逐段播放。本机 PowerPoint 16 已检查标题 API、段落点击和连续中间帧;用户于2026年10月8日在两台电脑的WPS中验证该演示播放与排版正常(未提供版本号);旧 Office 尚未验收。基础版式不是用户母版导入器。
width=960,height=540,即 16:9;宽高范围为 72~4032 点。x,y 为左上角,width,height 为尺寸;允许形状放到页面外,但不会替你修正裁切。"RRGGBB" 或 "#RRGGBB"。不接受 aardio/Office 的 COLORREF 数值,以免红蓝颠倒。fill=false 或 lineColor=false 表示不填充。rotation 使用角度,正数顺时针;自动归一化到一圈。每页 shapes 为数组,按数组顺序绘制,后面在上面。名称应唯一;id 默认从 2 递增,不能重复。每项:
| kind | 内容 |
|---|---|
text |
text 字符串或 paragraphs;透明文本框 |
shape |
geometry、fill、lineColor;可有文字 |
image |
本地 path 或 data 字节串;只支持 PNG/JPEG |
table |
rows 矩形二维数组;逐格保存值为文本,不重算公式 |
chart |
chart 指定类型、分类、系列;原生ChartML与独立内嵌XLSX |
通用字段包括 name,id,x,y,width,height,rotation,description,animation。文本样式包括 fontName,fontSize,color,bold,italic,align,valign,margin。对齐为 left/center/right/justify,垂直对齐为 top/center/bottom。矩形几何支持 rect,roundRect,ellipse,triangle,diamond,line,chevron,hexagon;线宽为 0~1584 点。
文本用 CR/LF 分段,垂直制表符 \v 表示软换行;TAB 保留。明确的 paragraphs 每项为字符串或 {text,runs,bullet,level,align}。运行 runs 每项为字符串或 {text,bold,italic,color,fontName,fontSize};运行内部不要放 CR/LF。替换不会把 & 当作预转义实体,所有文字按原样内容转义。非法 XML 控制字符、无效 UTF-8 和孤立代理项拒绝。
import fsys.openXml.pptx.builder;
var slides = [{shapes=[{
kind="text";name="Body";x=50;y=50;width=800;height=260;
paragraphs=[
{runs=[{text="中文 ";bold=true},{text="彩色文字";color="E55A33"}]},
{text='第一项\v软换行';bullet=true;level=0},
{text="第二项";bullet=true;level=1}
];
}]}];
return fsys.openXml.pptx.builder.write("/rich.pptx",slides);
图片原字节内嵌,不下载 URL、不转码。只给宽或高时保持比例;都省略时按 96 DPI 换算为 point。两者都给时,fit="stretch" 默认保持旧的拉伸行为;0.7.0 起可用 contain 完整等比放入目标框,或 cover 等比铺满并裁切。imageAlignX/imageAlignY 在 0..1 指定锚点,默认 0.5 居中(0=左/上,1=右/下)。contain 改变实际图片形状的尺寸与位置,空余区域没有额外图片背景;cover 保持指定框,用原图裁切比例而不重编码。0.8.0 起内容相同的图片(无论来自 path 还是 data)只嵌入一份,所有页面共用同一媒体部件。
表格每行宽度须一致。中间的 null 显示为空文本,0/false/空串 分别保留;尾部空格请用 "" 明确表示,因为尾部 null 不保留数组长度。0.11.0 起可用 merges 指定矩形合并,不做自适应列宽。默认等分行列,0.7.0 起支持下述细化样式。
fill/background/cellFill/bandFill 支持:
"RRGGBB" 或 false:纯色或无填充,兼容旧调用。{color="FFFFFF";opacity=0.35}:纯色带透明度;opacity 是不透明度,范围 0..1,0 完全透明,1 不透明。{angle=45;stops=[{position=0;color="123456"},{position=1;color="468ACE";opacity=0.8}]}:线性渐变。2~32 个 stop,position 在 0..1 且升序排列;各点 opacity 默认 1。角度使用度数,0 从左向右,90 从上向下,随形状旋转。暂不支持径向渐变、纹理;0.10.0 起支持简单外阴影 shadow。margin 可为单个 point 数值或 {left,right,top,bottom}。形状未指定的边默认 4 point,表格默认 3 point;0 被保留。lineSpacing 为百分比(100=单倍,125=1.25 倍),范围 1~1000。spaceBefore/spaceAfter 为段前/后距离(point,0~1584)。这三个字段可写在形状上,也可在各段落上覆盖;不指定时保持旧行为。builder.check 预检文字溢出(见下文)。columnWidths/rowHeights 为 point 数组,数量须分别等于列/行数,合计须等于表格 width/height(容差 0.01 point)。省略则等分;舍入余量归末项。header={fill,color,bold,...} 为第一行样式;bandFill 为隔行底色。存在 header 时,从第二条正文行(表格第 3 行)开始间隔填色,否则第 2 行开始。{text,paragraphs,fill,color,bold,fontSize,margin,valign,...}。优先级:表格默认 → 隔行 → 表头 → 单元格。false 与 0 可显式覆盖;空 cell 表表示空文本。borderColor 为 RRGGBB,borderWidth 为 point,默认 0.5;可以在表格、header 或单元格中指定四边同样式边框。import fsys.openXml.pptx.builder;
var slides=[{
background="F5F7FB";
shapes=[{
kind="shape";name="Title";x=50;y=40;width=860;height=110;
fill={angle=20;stops=[{position=0;color="15314F"},{position=1;color="36798B"}]};
text="可编辑的排版与样式";fontSize=32;color="FFFFFF";
margin={left=24;right=24;top=18;bottom=18};valign="center";
},{
kind="table";name="Grid";x=50;y=190;width=860;height=180;
columnWidths=[220,320,320];rowHeights=[50,65,65];
fontSize=20;valign="center";margin=12;
cellFill="FFFFFF";bandFill="E9EFF7";
header={fill="203C61";color="FFFFFF";bold=true};
rows=[["项目","说明","数值"],["保留类型","零不是缺失值",0],
["局部强调",{text="可单独设置颜色";color="168A76";bold=true},false]];
}];
}];
return fsys.openXml.pptx.builder.write("/styled.pptx",slides);
完整 6 页示例:~/examples/File/OpenXML/pptx-design.aardio,资源在同目录 .pptx-design/。包含封面、叙事卡片、形状柱状图、图片适配、原生表格和点击动画。示例图表数据为虚构展示数据;柱条是普通形状,不是含工作簿的原生 chart。
builder.check(slides,options,checkOptions) 接收与 write 完全相同的参数,不启动 Office、不写文件、不修改输入。先做与生成相同的校验(不合法时返回 null,err),再估算版式:
| code | 含义 |
|---|---|
overflow |
文字估算高度超过文本区(已扣除内边距);内边距大于形状为 error,其余为 warning |
tableGrow |
表格某些行放不下内容,PowerPoint 打开时会自动增高;给出每行需要的高度与总增高 |
offSlide |
形状(含旋转后的外接框、表格自动增高后的高度)超出页面 |
overlap |
两个含文字的形状或表格的区域相交;文字叠在无字卡片、图片上不报 |
import fsys.openXml.pptx.builder;
var slides=[{shapes=[
{kind="text";name="Title";x=40;y=40;width=300;height=40;fontSize=20;
text="这个标题太长了,三百点宽的文本框放不下这么多字"}
]}];
var report,err=fsys.openXml.pptx.builder.check(slides);
if(!report) return null,err;
for i,item in report.issues {
print(item.code,item.message); // overflow 第 1 页形状 Title:文字可能溢出:约需 48pt,可用 32pt(2 行)
}
return report.ok;
返回 {ok,issues,counts,errors,warnings,missingFonts}。每个问题含 code,severity,message,slide,shape 以及细节字段(needed/available/lines、rows/grow、bounds、other/area)。checkOptions 可设 tolerance=0.5(point)、overlapMinArea=4、ignore=["overlap"];单个形状可设 checkIgnore=true 或 checkIgnore=["overflow"],表示该处的重叠或溢出是有意设计。missingFonts 列出系统缺少、测量时已回退到微软雅黑的字体。
估算原理与精度:用 GDI+ 通用排版格式测行数,再按 PowerPoint 行高规律计算(单倍行高 = 1.2×字号;百分比行距时文本框首行只计入约 48% 的额外行距;表格行高 = 内容高度 + 单元格上下边距,空单元格仍占一行)。与本机 PowerPoint 16 实测对照:设计演示 54 个文本框高度平均误差约 0.1%、最大约 1.6%;24 个自动折行样本中 21 个行数完全一致,其余 3 个都是中文窄栏多估 1 行(PowerPoint 允许行尾标点悬挂到边界外,GDI+ 不支持),从未少估;表格自动增高后的 10 行行高全部一致。这些样本中没有少估,但不保证对所有字体与输入都不漏报。它仍是估算,不是排版引擎:不模拟逐运行混排、字距、首字下沉,仅针对 PowerPoint 实测过;WPS 未逐项校准。
fontName 同时用于拉丁、东亚、复杂文种;也可用 fontNameLatin/fontNameEa/fontNameCs 分别指定,例如英文用 Segoe UI、中文用微软雅黑。可写在运行、段落、形状或 options 上,逐级继承;某一级显式写了 fontName 会覆盖外层的分文种设置。headingFontName(或 headingFontNameLatin/headingFontNameEa)单独指定。lang 默认 zh-CN,可在形状或 options 上改为 en-US、ja-JP 等 BCP 47 标签,影响拼写检查与断词。options.fontSize;可用 options.notesFontSize 指定。lineDash 为 solid/dot/dash/lgDash/dashDot/lgDashDot/lgDashDotDot/sysDash/sysDot/sysDashDot/sysDashDotDot;lineStart/lineEnd 为箭头类型 triangle/stealth/diamond/oval/arrow(true 表示三角),或 {type,size},size 为 sm/med/lg。geometry="line" 时可直接给起点 x,y 与终点 x2,y2,边界框与翻转自动计算,斜线不必再换算旋转角;线条默认无填充。第 2 页 形状 Title:无效的生成参数:fontSize、第 1 页 切换:未支持的幻灯片切换:unknown,不再夹带库文件路径与行号。import fsys.openXml.pptx.builder;
var slides=[{notes="备注默认 12pt";shapes=[
{kind="text";name="Mixed";x=60;y=60;width=600;height=60;fontSize=28;
text="Native PPTX 原生生成";fontNameLatin="Segoe UI";fontNameEa="Microsoft YaHei"},
{kind="shape";name="Arrow";geometry="line";x=80;y=300;x2=420;y2=180;
lineColor="E55A33";lineWidth=2;lineDash="dash";lineEnd="triangle"}
]}];
return fsys.openXml.pptx.builder.write("/fonts-lines.pptx",slides,{headingFontName="SimHei"});
shape.animation 可为一个动画表或数组,作用于自身。slide.animations 为按页面指定顺序的动画数组,target 用形状 id 或唯一名称;它追加在形状自身动画之后。
支持:
| effect | 默认类别 | 说明 |
|---|---|---|
appear |
entrance | 立即出现;exit 为立即消失 |
fade |
entrance | 淡入/淡出 |
fly |
entrance | 从指定侧飞入;exit 飞向指定侧 |
wipe |
entrance | 擦除;exit 为退场擦除 |
zoom |
entrance | 缩放并淡入;exit 缩小并淡出 |
spin |
emphasis | angle 默认 360 度,可负值 |
grow |
emphasis | scale 默认 150,表示百分比 |
类别字段 category 为 entrance/exit/emphasis;spin/grow 只属于 emphasis,其他属于 entrance/exit。direction 为 top/right/bottom/left,飞入与擦除默认 bottom。这些是本库已验证的名称,不是 COM 的 MsoAnimEffect 数值;COM 常量与 XML presetID 不可混用。
trigger 为 click/with/after:点击开始、与同组前动画同步、等前一并行组结束;首个 with/after 可自动开始。duration/delay 为秒,默认 0.5/0;appear 固定 1 毫秒。after 的起点等待前一并行组最长动画(包括延迟)结束。每次新 click 建立新点击组。
import fsys.openXml.pptx.builder;
var slides=[{shapes=[{
kind="shape";name="Badge";x=330;y=160;width=220;height=140;
geometry="roundRect";fill="4472C4";text="动画";color="FFFFFF";
align="center";valign="center";
animation=[
{effect="fly";direction="left";trigger="with";duration=0.7},
{effect="spin";angle=90;trigger="after";duration=0.5},
{effect="fade";category="exit";trigger="click";duration=0.4}
];
}]}];
return fsys.openXml.pptx.builder.write("/animated.pptx",slides);
支持整形状及逐段落动画、Morph 与明确的 fade 兼容回退;不支持交互触发器、声音、自定义运动路径或所有 PowerPoint 特效。未知效果明确报错,不静默降级。尚未覆盖的复杂时间轴可用 COM 辅助。
transition 可含 effect,duration,direction,orientation,advanceOnClick,advanceAfter,option。效果为 none/cut/fade/push/wipe/split/morph;Morph 及其 fade 回退见上面的 0.9.0 一节;push/wipe 用四方向,split 用 direction=in/out,orientation=horz/vert。duration/advanceAfter 为秒,advanceOnClick 默认 true。写出 Office 2010 扩展 Choice 与标准 Fallback;老软件只得到 fast/med/slow 分类,不保证精确时长。
notes 字符串生成逐页备注,空字符串仍生成备注部件;不传则没有。备注母版有独立主题,避免 SDK 良构但 PowerPoint 不能打开的兼容性问题。hidden=true 保存隐藏页。
maxEntries=10000,maxPartBytes=16777216,maxWriteBytes=134217728;最高 100000 项、128 MiB/件、1 GiB 累计,均为正整数。buildParts(slides,options) 返回部件数组,适合测试/受控扩展,不是完整布局/样式对象模型。.ppt、宏、上述四种二维图以外的图表、SmartArt 或复杂主题/母版;不自动分页、不自动缩字、不嵌入字体、不渲染 PDF/图片。文字测量只用于 check 预警,不改变生成结果。