本文告訴大家如何讀取 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" preset 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" preset 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" preset 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" preset)
可以使用以下代碼讀取
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 =https://www.cnblogs.com/lindexi/archive/2021/07/02/= TimeNodeValues.TmingRoot)
{
// 這是符合約定
// nodeType="tmRoot"
}
if (commonTimeNode?.ChildTimeNodeList == null) return;
// 理論上只有一項,而且一定是 SequenceTimeNode 型別
var sequenceTimeNode = commonTimeNode.ChildTimeNodeList.GetFirstChild<SequenceTimeNode>();
var mainSequenceTimeNode = sequenceTimeNode.CommonTimeNode;
if (mainSequenceTimeNode?.NodeType?.Value =https://www.cnblogs.com/lindexi/archive/2021/07/02/= 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().CommonTimeNode.ChildTimeNodeList
.GetFirstChild().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選項)"
}
本文上面代碼放在 github 和 gitee 歡迎訪問
可以通過如下方式獲取本文的源代碼,先創建一個空檔案夾,接著使用命令列 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 解壓縮檔案為檔案夾工具 工具協助測驗的,這個工具是開源免費的工具,歡迎使用
更多請看 Office 使用 OpenXML SDK 決議檔案博客目錄
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/288818.html
標籤:.NET技术
上一篇:代碼重構與單元測驗(一)
下一篇:基于C#的多邊形沖突檢測
