偶遇需要解析 PPT为单张图片
其中,对于包含动画的PPT页,分别对动画最后效果进行截取,即每个连续动画截取 (动画N个)N+1(原图)张
http://git.oschina.net/jiailiuyan/OfficeDecoder
using System.Collections.Generic; using System.Drawing; using System.IO; using System.Reflection; using Aspose.Slides; using Aspose.Slides.Animation; namespace Helpers { public static class PPTHelper { /// <summary> 获取 PPT 文档单页中的Shape,此项为动画的触发项 </summary> /// <param name="ieffect"></param> /// <returns></returns> private static AutoShape GetAutoShape(IEffect ieffect) { AutoShape autoshape = null; var effect = ieffect as Effect; var flag = BindingFlags.Instance | BindingFlags.NonPublic; // 在 IEffect 中,PPTXUnsupportedProps 是获取触发项的属性 var props = effect.TextAnimation.GetType().GetProperty("PPTXUnsupportedProps", flag); if (props != null) { var animation = props.GetValue(effect.TextAnimation, null); // 由于 dll 混淆后,无法直接获取属性的名称且触发项被设置为了保护项,因此需要反射 ishape_0 获取 var ishapefield = animation.GetType().GetField("ishape_0", flag); var ishape = ishapefield.GetValue(animation); autoshape = ishape as AutoShape; } return autoshape; } /// <summary> 设置默认的 Slide 显示内容,在有动画的情况下, ISlide 显示的是编辑状态下最终呈现的,因此要修改其属性为动画播放状态初始界面 </summary> /// <param name="islide"></param> /// <returns></returns> private static bool SetDefaultSlide(ISlide islide) { // ISlide 中的 Timeline.MainSequence 记录的是动画项 var slidecount = islide.Timeline.MainSequence.Count; if (slidecount == 0) { return false; } for (int i = 0; i < slidecount; i++) { var ieffect = islide.Timeline.MainSequence[i]; var autoshape = GetAutoShape(ieffect); foreach (var behavior in ieffect.Behaviors) { // Behaviors 中暂时只需要判断 SetEffect 项,因为其他项设置的是缓动和位置,因此无需处理 var seteffect = behavior as SetEffect; if (seteffect != null) { //因为在此有动画设置此项为可见,反推之,此项默认应该隐藏 if (seteffect.To.ToString() == "visible") { autoshape.Hidden = true; } continue; } } } return true; } public static List<string> ConvertToImages(string pptfile, string savedirectory = "") { // 返回的图片绝对路径集合 List<string> images = new List<string>(); // 获取 Word 文件名称 var pptname = System.IO.Path.GetFileNameWithoutExtension(pptfile); // 如果指定了保存路径,则使用传入的路径,否则在 Pdf 文件的同级创建同名文件夹当作保存路径 savedirectory = string.IsNullOrWhiteSpace(savedirectory) ? System.IO.Path.GetDirectoryName(pptfile) : savedirectory; savedirectory = System.IO.Path.Combine(savedirectory, pptname); // 防止保存的路径不存在因此创建保存文件夹 Directory.CreateDirectory(savedirectory); var pres = new Presentation(pptfile); int pptcount = pres.Slides.Count; for (int p = 0; p < pptcount; p++) { var item = pres.Slides[p]; var imagefile = System.IO.Path.Combine(savedirectory, p + ".jpg"); if (!SetDefaultSlide(item)) { // 获取 2 倍的图像,用以解决 PPT 内容过小时分辨率过小 ,下同 item.GetThumbnail(2.0f, 2.0f).Save(imagefile); images.Add(imagefile); continue; } imagefile = System.IO.Path.Combine(savedirectory, p + "_0.jpg"); item.GetThumbnail(2.0f, 2.0f).Save(imagefile); images.Add(imagefile); // 在此每一个动画需要截图一次,因为每一个动画都有自己的显示内容 var slidecount = item.Timeline.MainSequence.Count; for (int i = 0; i < slidecount; i++) { var ieffect = item.Timeline.MainSequence[i]; var autoshape = GetAutoShape(ieffect); try { foreach (var behavior in ieffect.Behaviors) { var seteffect = behavior as SetEffect; if (seteffect != null) { //由于此属性标识当前项可见,于是需要还原状态用以截图 autoshape.Hidden = seteffect.To.ToString() != "visible"; continue; } } } catch { } imagefile = System.IO.Path.Combine(savedirectory, p + "_" + i + ".jpg"); item.GetThumbnail(2.0f, 2.0f).Save(imagefile); images.Add(imagefile); } } return images; } /// <summary> 获取 PPT 中包含动画的所有可显示的 Bitmap </summary> /// <param name="path"> PPT 文件路径 ,可以为 .pptx .ppt .pptm </param> /// <returns> 包含了所有动画页的图像 </returns> public static List<Bitmap> GetPPTImages(string path) { var bmps = new List<Bitmap>(); var pres = new Presentation(path); foreach (var item in pres.Slides) { if (!SetDefaultSlide(item)) { // 获取 2 倍的图像,用以解决 PPT 内容过小时分辨率过小 ,下同 bmps.Add(item.GetThumbnail(2.0f, 2.0f)); continue; } bmps.Add(item.GetThumbnail(2.0f, 2.0f)); // 在此每一个动画需要截图一次,因为每一个动画都有自己的显示内容 var slidecount = item.Timeline.MainSequence.Count; for (int i = 0; i < slidecount; i++) { var ieffect = item.Timeline.MainSequence[i]; var autoshape = GetAutoShape(ieffect); try { foreach (var behavior in ieffect.Behaviors) { var seteffect = behavior as SetEffect; if (seteffect != null) { //由于此属性标识当前项可见,于是需要还原状态用以截图 autoshape.Hidden = seteffect.To.ToString() != "visible"; continue; } } } catch { } bmps.Add(item.GetThumbnail(2.0f, 2.0f)); } } return bmps; } } }