# PPTX 有限编辑与安全另存

`fsys.openXml.pptx.editor` 在 0.6.0 提供文本替换、页序调整、同类型图片替换，以及显式动画/切换替换。不需要 Office/WPS；使用系统 MSXML 与公共 ZIP 读写库。

**0.11.0** 增加同文稿复制/删除页面、保留格式的矩形表格填值，以及横向/纵向/矩形合并。快速用法及限制见 [模板与数据](data.html)。不包含跨文稿母版导入、图表创建或近似预览。

## 跨文本运行替换

```aardio
import fsys.openXml.pptx.editor;
var doc,err=fsys.openXml.pptx.editor.open("/input.pptx");
if(!doc) return null,err;
var count,err=doc.replaceText("{{Name}}","新名称",{includeNotes=true});
if(count===null){doc.close();return null,err;}
var path,err=doc.save("/edited.pptx");
doc.close();
if(!path) return null,err;
return {path=path;count=count};
```

搜索为大小写敏感字面字符串。可匹配被拆在同段落相邻 `a:r/a:t` 内的占位符，替换文字继承第一个命中运行的格式，未命中部分保留原运行格式。不会把整段文字扁平化重写。

- 默认只处理幻灯片，`includeNotes=true` 加入对应备注。
- `options.slides=[1,3]` 只处理指定页，省略为全部页；[] 不处理。
- 不跨段落、软换行或 `a:fld` 域，不接受搜索/替换中的 CR/LF；不触碰母版文字或图表对象。
- 返回替换次数，**0 是正常成功值**，不要用 `if(!count)` 判断失败；失败为 `null,err`。
- 一次替换先处理并校验全部目标，再提交内存修改；失败不部分修改。

## 页序、形状与动画

```aardio
import fsys.openXml.pptx.editor;
var doc,err=fsys.openXml.pptx.editor.open("/input.pptx");
if(!doc) return null,err;
var slides,err=doc.listSlides();
if(!slides){doc.close();return null,err;}
var order=[];
for(i=#slides,1,-1) table.push(order,i);
var ok,err=doc.reorderSlides(order);
if(!ok){doc.close();return null,err;}
var path,err=doc.save("/reordered.pptx");
doc.close();
return path,err;
```

`reorderSlides(order)` 要求全部页号恰好出现一次，仅改主文档 `sldIdLst`，不删除、复制页面或清理孤儿媒体；现有备注、动画、图片关系仍关联原页面。

`listSlides()` 返回 index,id,partName,relationshipId；`listShapes(page)` 返回 id,name,kind,text,hasText，按 XML 形状树及分组递归顺序，不是视觉排序。

`setAnimations(page,effects,replaceExisting=false)` 使用 [生成器动画](../builder/index.html) 的相同描述。若原页已有时间轴，**默认报错**；明确传 true 才完整替换。[] 清空，不尝试合并未知时间轴或保留部分特效。

`setTransition(page,options,replaceExisting=false)` 同理，null 清空；新的切换写在 timing 之前。对于同时含其他内容的 AlternateContent，若其中含 transition，完整替换该块。两项写入只支持 Transitional；Strict 文档可以文本/页序编辑，但拒绝混入 Transitional 动画节点。

## 图片替换

`replaceImage(page,target,dataOrPath)` 以图片 id 或唯一 name 选择图片，替换其现有内部媒体部件。只接受与原部件相同的 PNG/JPEG 类型，并检查可解码；不访问外链图片、不调整裁剪和位置。

返回 `{partName,sharedPart=true}`。**同一媒体部件被其他页/形状引用时，它们也会改变**；本接口不是“仅替换这一张形状”的自动克隆。0.11.0 的 `copySlide` 会为新页独立复制已支持的图片/图表/工作簿依赖，与原页隔离；但副本内部多个形状仍可共用一份媒体。单张图片的自动拆分、图表数据编辑仍不在 replaceImage 的范围内。

## 保存与保留

- `open/read` 不改源件；`save` 默认另存、不覆盖已有目标。即使 `overwrite=true` 也拒绝源路径及可识别的硬链接别名。
- 保留所有未修改部件的原始解压字节，使用 CRC 检查后重新压缩，不要求 ZIP 容器字节、压缩参数、时间戳或目录项相同。
- 未修改的未知部件、宏、嵌入对象保留但不执行；输入含包数字签名时拒绝，因为修改会使签名失效。宏数字签名不等于包数字签名。
- 被修改 XML 由 MSXML 序列化，会改变 XML 声明、属性排列、实体表达形式等；不承诺修改部件逐字节不变。
- `changedParts()` 列出显式改动部件（包含已删除的部件名）；`close()` 必须调用，可以重复关闭。编辑对象及 COM 节点只在当前线程使用。
- 默认每件 16 MiB、一个读取会话累计 128 MiB，写入累计 128 MiB。每次 save 重新打开只读包，重复保存不继承上次保存的读取预算。限额可显式提高到 128 MiB/件、1 GiB 累计。
- 保存失败不提交半成品，旧输出和源件保留；不吞成空成功。不是任意大小流式 raw-copy 编辑器，不校验完整 Office 语义或更新缩略图/应用统计/域缓存。

低层包替换见 [fsys.openXml.editor](../../editor/index.html)。`fsys.openXml.pptx.edit` 与技能 `editPptx` 为便捷入口。
