dotnet OpenXML 读取 PPT 主序列进入退出强调动画
程序员文章站
2022-03-26 09:11:12
本文告诉大家如何读取 PPT 文件里面,放在主动画序列 MainSequence 的进入和退出和强调的动画,和在 OpenXML 里面的存放方式 ......
本文告诉大家如何读取 ppt 文件里面,放在主动画序列 mainsequence 的进入和退出和强调的动画,和在 openxml 里面的存放方式
如以下的课件内容,给一个元素添加了进入强调退出的动画,动画之间没有相关影响,通过点击触发动画,如下图
大概的动画内容如下
<p:timing> <p:tnlst> <p:par> <p:ctn id="1" dur="indefinite" restart="never" nodetype="tmroot"> <p:childtnlst> <p:seq concurrent="1" nextac="seek"> <p:ctn id="2" dur="indefinite" nodetype="mainseq"> <p:childtnlst> <p:par> <p:ctn id="3" fill="hold"> <p:stcondlst> <p:cond delay="indefinite" /> </p:stcondlst> <p:childtnlst> <p:par> <p:ctn id="4" fill="hold"> <p:stcondlst> <p:cond delay="0" /> </p:stcondlst> <p:childtnlst> <p:par> <p:ctn id="5" presetid="1" presetclass="entr" presetsubtype="0" fill="hold" grpid="0" nodetype="clickeffect"> <p:stcondlst> <p:cond delay="0" /> </p:stcondlst> <p:childtnlst> <!-- 忽略代码--> </p:childtnlst> </p:ctn> </p:par> </p:childtnlst> </p:ctn> </p:par> </p:childtnlst> </p:ctn> </p:par> <p:par> <p:ctn id="7" fill="hold"> <p:stcondlst> <p:cond delay="indefinite" /> </p:stcondlst> <p:childtnlst> <p:par> <p:ctn id="8" fill="hold"> <p:stcondlst> <p:cond delay="0" /> </p:stcondlst> <p:childtnlst> <p:par> <p:ctn id="9" presetid="25" presetclass="emph" presetsubtype="0" fill="hold" grpid="2" nodetype="clickeffect"> <p:stcondlst> <p:cond delay="0" /> </p:stcondlst> <p:childtnlst> <!-- 忽略代码--> </p:childtnlst> </p:ctn> </p:par> </p:childtnlst> </p:ctn> </p:par> </p:childtnlst> </p:ctn> </p:par> <p:par> <p:ctn id="14" fill="hold"> <p:stcondlst> <p:cond delay="indefinite" /> </p:stcondlst> <p:childtnlst> <p:par> <p:ctn id="15" fill="hold"> <p:stcondlst> <p:cond delay="0" /> </p:stcondlst> <p:childtnlst> <p:par> <p:ctn id="16" presetid="10" presetclass="exit" presetsubtype="0" fill="hold" grpid="1" nodetype="clickeffect"> <!-- 忽略代码--> </p:ctn> </p:par> </p:childtnlst> </p:ctn> </p:par> </p:childtnlst> </p:ctn> </p:par> </p:childtnlst> </p:ctn> <!-- 忽略代码--> </p:seq> </p:childtnlst> </p:ctn> </p:par> </p:tnlst> <!-- 忽略代码--> </p:timing>
根据 ctn
也就是 openxml sdk 定义的 commontimenode
类型的 presetclass 属性可以了解到,动画 id 是 5 的是进入动画,动画 id 是 9 的是强调动画,动画 id 是 10 的是退出动画
可以看到在 ppt 里面,多个不同的动画,这些动画没有关联,也就是没有在上一个播放完成后,而是通过点击触发的,放在主序列的动画的内容大概如下
<p:timing> <p:tnlst> <p:par> <p:ctn id="1" dur="indefinite" restart="never" nodetype="tmroot"> <p:childtnlst> <p:seq concurrent="1" nextac="seek"> <p:ctn id="2" dur="indefinite" nodetype="mainseq"> <p:childtnlst> <p:par> <!-- 进入动画--> </p:par> <p:par> <!-- 强调动画--> </p:par> <p:par> <!-- 退出动画--> </p:par> </p:childtnlst> </p:ctn> <!-- 忽略代码--> </p:seq> </p:childtnlst> </p:ctn> </p:par> </p:tnlst> <!-- 忽略代码--> </p:timing>
如上面的内容,大概可以理解存放的方式了,只是在 ppt 里面,有多个 paralleltimenode 和 commontimenode 的嵌套。从 mainseq 也就是 mainsequence 主动画序列以下,获取到的实际的进入动画,是经过了如下路径才能获取
ctn (mainseq) -> childtnlst -> par -> ctn (id="3") -> childtnlst -> par -> ctn (id="4") -> childtnlst -> par -> ctn (id="5" presetclass="entr")
可以使用以下代码读取
static void main(string[] args) { using var presentationdocument = documentformat.openxml.packaging.presentationdocument.open("test.pptx", false); var presentationpart = presentationdocument.presentationpart; var slidepart = presentationpart!.slideparts.first(); var slide = slidepart.slide; var timing = slide.timing; // 第一级里面默认只有一项 var commontimenode = timing?.timenodelist?.paralleltimenode?.commontimenode; if (commontimenode?.nodetype?.value == timenodevalues.tmingroot) { // 这是符合约定 // nodetype="tmroot" } if (commontimenode?.childtimenodelist == null) return; // 理论上只有一项,而且一定是 sequencetimenode 类型 var sequencetimenode = commontimenode.childtimenodelist.getfirstchild<sequencetimenode>(); var mainsequencetimenode = sequencetimenode.commontimenode; if (mainsequencetimenode?.nodetype?.value == timenodevalues.mainsequence) { // [timeline 对象 (powerpoint) | microsoft docs](https://docs.microsoft.com/zh-cn/office/vba/api/powerpoint.timeline ) // mainsequence 主动画序列 var mainparalleltimenode = mainsequencetimenode.childtimenodelist; foreach (var openxmlelement in mainparalleltimenode) { // 并行关系的 if (openxmlelement is paralleltimenode paralleltimenode) { var timenode = paralleltimenode.commontimenode.childtimenodelist .getfirstchild<paralleltimenode>().commontimenode.childtimenodelist .getfirstchild<paralleltimenode>().commontimenode; switch (timenode.presetclass.value) { case timenodepresetclassvalues.entrance: // 进入动画 break; case timenodepresetclassvalues.exit: // 退出动画 break; case timenodepresetclassvalues.emphasis: // 强调动画 break; case timenodepresetclassvalues.path: // 路由动画 break; case timenodepresetclassvalues.verb: break; case timenodepresetclassvalues.mediacall: // 播放动画 break; default: throw new argumentoutofrangeexception(); } } } } // 文档规定,必须存在一个attributenamelist列表,一定存在attributename元素,如果有多个只取第一个元素。 // 见"[ms-oi 29500].pdf 第2.1.1137章节(g选项)" }
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init git remote add origin https://gitee.com/lindexi/lindexi_gd.git git pull origin 2c06ddf74e45c31ad7842dd06dc09bcc67b6142e
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源
git remote remove origin git remote add origin https://github.com/lindexi/lindexi_gd.git
获取代码之后,进入 pptxdemo 文件夹
以上的测试使用的 ppt 课件也放在此文件夹
本文的属性是依靠 dotnet openxml 解压缩文档为文件夹工具 工具协助测试的,这个工具是开源免费的工具,欢迎使用