回顾一下上文结尾的问题:如何给文档设置一个合适的封面图?其中一个解决方案就是,获取Office文件内部的图片作为封面。这里就详细介绍下获取图片的几种方式,以及他们各自的优缺点。

PS:因为之前用VSTO开发过PPT的插件程序,所以对PPT的COM ApI比较熟悉,所以下面的样例和代码都以操作PPT文档为主,Word、PPT、Excel之间的结构差异还是很大的,详细的文档描述还是要去官网查看(传送门)。

基于Office的解决方案

通过Office COM API打开PPT文档,遍历每个幻灯片(Slide)的每个形状(Shape),然后通过剪切板将包含图片的形状复制到内存中,再保存到本地目录。

/// <summary>
/// 导出PPT文件中图片到目标文件夹下
/// </summary>
/// <param name="sourcePath">PPT文件路径</param>
/// <param name="targetDir">目标文件夹</param>
public static void GetPPTImages(string sourcePath, string targetDir)
{
var app = new PowerPoint.Application();
var persentation = app.Presentations.Open(sourcePath, WithWindow: MsoTriState.msoFalse);
int num = 1;
for (int i = 1; i < persentation.Slides.Count; i++)
{
var slide = persentation.Slides[i];
for (int j = 1; j < slide.Shapes.Count; j++)
{
var shape = slide.Shapes[j];
if (shape.Type == MsoShapeType.msoPicture || shape.Fill.Type == MsoFillType.msoFillPicture)
{
shape.Copy();//shape自带的方法,复制到剪切板中
if (Clipboard.ContainsImage())
{
var imgPath = Path.Combine(targetDir, num + ".jpg");
Clipboard.GetImage().Save(imgPath, System.Drawing.Imaging.ImageFormat.Jpeg);
num++;
}
}
}
}
persentation.Close();
}

上面代码中有几个需要注意的地方:

  1. SlidesShapes都是从1开始遍历的
  2. Clipboard对象在System.Windows.Forms.dll
  3. PPT文件中图片有两种存在的方式,单独为形状的图片(shape.Type == MsoShapeType.msoPicture)和作为形状背景的图片(shape.Fill.Type == MsoFillType.msoFillPicture)
  4. 使用shape.Copy()来复制形状到剪切板,而不能直接通过Clipboard.SetDataObject(shape)

简单介绍下上面代码的实现思路,就好像用Office软件打开了PPT文件,然后选择包含图片的形状,Ctrl + C然后Ctrl + V到本地。有兴趣的同学可以尝试下,在PPT中复制图片,然后在微信对话框中粘贴。

当然这种做法有着很大的缺陷:

  1. 图片不全,通过上面的判定方式获取到的只是一部分的图片并没有把所有文件都保存到本地
  2. 图片异常,如果尝试过,将PPT中图片复制到微信里,你会发现它是把整个形状生成了一张图片。比如在一个文本框中输入文字,然后再加上图片背景,最后复制到出来的就是包含了文字的一张图片。
  3. 图片模糊,复制出来的图片分辨率有限,不再是原来的图片分辨率了。

总而言之,该解决方案仅供学习参考,实际应用还是不合适的!!!

基于OpenXml的解决方案

Office Open XML 是由Microsoft开发的一种以XML为基础并以ZIP格式压缩的电子文件规范,支持文件、表格、备忘录、幻灯片等文件格式。

简单来说一个PPT文件(.pptx后缀),其实是一个ZIP格式压缩的电子文件,压缩文件内通过XML标记了文档的内容,比如,引用的图片、文字的排列方式等等。

常用的几种Office文件中的,Word文件有.doc.docx两种后缀,PowerPoint文件有.ppt.pptx两种后缀,Excel文件有.xls.xlsx两种后缀。这其实就是文件版本的差异。 OpenXml也只能用在2007及以后的文件版本中(后缀为.docx.pptx.xlsx)。

测试:准备同一PPT文件分别另存为.ppt.pptx两个版本,直接修改文件后缀为.zip



PS:图片资源存放路径 /ppt/media/


代码(目前只有获取PPT和Word文件图片的,Excel的暂时未考虑):

先通过Nuget包管理安装需要用到的包

DocumentFormat.OpenXml

using DocumentFormat.OpenXml.Packaging;

/// <summary>
/// 导出PPT文件中所有图片
/// </summary>
/// <param name="sourcePath">源文件路径</param>
/// <param name="targetDir">目标文件存放目录</param>
/// <returns></returns>
public static void ExportPPTImages(string sourcePath,string targetDir)
{
using (PresentationDocument presentationDocument = PresentationDocument.Open(sourcePath, isEditable: false))
{
PresentationPart presentationPart = presentationDocument.PresentationPart;
DocumentFormat.OpenXml.Presentation.Presentation presentation = presentationPart.Presentation;
List<ImagePart> list = new List<ImagePart>();
foreach (DocumentFormat.OpenXml.Presentation.SlideId item in presentation.SlideIdList.OfType<DocumentFormat.OpenXml.Presentation.SlideId>())
{
SlidePart slidePart = presentationPart.GetPartById(item.RelationshipId) as SlidePart;
list.AddRange(slidePart.ImageParts);
}
List<IGrouping<string, ImagePart>> list2 = list.GroupBy(d => d.Uri.OriginalString).ToList(); //导出PPT所有的图片
for (int i = 0; i < list2.Count; i++)
{
ImagePart imagePart = list2[i].FirstOrDefault();
string tempFileName = Path.Combine(targetDir, $"image_{i}.jpg");
using (Stream stream = imagePart.GetStream(FileMode.Open))
{
using (Bitmap bitmap = new Bitmap(stream))
{
bitmap.Save(tempFileName, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
//presentation.Save();
}
} /// <summary>
/// 导出Word文件中所有图片
/// </summary>
/// <param name="sourcePath">源文件路径</param>
/// <param name="targetDir">目标文件存放目录</param>
/// <returns></returns>
public static void ExportWordImages(string sourcePath,string targetDir)
{
using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(sourcePath, isEditable: false))
{
var list2 = wordDocument.MainDocumentPart.ImageParts.GroupBy(d => d.Uri.OriginalString).ToList();
for (int i = 0; i < list2.Count; i++)
{
ImagePart imagePart = list2[i].FirstOrDefault();
string tempFileName = Path.Combine(targetDir, $"image_{i}.jpg");
using (Stream stream = imagePart.GetStream(FileMode.Open))
{
using (Bitmap bitmap = new Bitmap(stream))
{
bitmap.Save(tempFileName, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
}
}

可以通过OpenXml获取到Office XML的抽象类型,当然也可以对内容进行编辑啦~有兴趣的可以去微软OpenXml官网了解下,这里就不过多介绍了。

综上所述,这个解决方案还是很靠谱的,可以直接用于生产环境。还有缺陷就是无法处理2003版本的Office文件,这个也只能通过转换文件为新版本再来处理了。

基于第三方插件的解决方案

好吧,第三方插件又来了,对没错说的就是你Spire。关于插件的介绍都已经写在上一篇文章中了,这里也不啰嗦了,直接上代码(这里只是做个引子,记录下PPT文件的代码,其他的自己去官网找Demo吧)。

using Spire.Presentation;

/// <summary>
/// 导出PPT文件中所有图片
/// </summary>
/// <param name="sourcePath">源文件路径</param>
/// <param name="targetDir">目标文件存放目录</param>
/// <returns></returns>
public static void ExportPPTImages2(string sourcePath, string targetDir)
{
using (Presentation pres = new Presentation())
{
pres.LoadFromFile(sourcePath);
for (int i = 0; i < pres.Images.Count; i++)
{
Image image = pres.Images[i].Image;
string tempFileName = Path.Combine(targetDir, $"image_{i}.jpg");
image.Save(tempFileName);
}
}
}

偷偷的说:用Spire正式版插件导出来的图片没有水印,可以放心使用~

总结

上面已经介绍了Office 2007及之后版本的文件其实是.zip格式的压缩文件,将所有图片提取出来后发现,一个100M的PPT文件,居然藏了600M的图片,有点意思啊!思来想去感觉一个100M的文件还是太大,那么在不影响效果的情况下,是不是可以调整处理下文件中的图片大小,来达到压缩整个文件大小的目的呢?下篇再来细细描述吧~~~

Office系列(2)---提取Office文件(Word、PPT)中的所有图片的更多相关文章

  1. Office系列---将Office文件(Word、PPT、Excel)转换为PDF文件,提取Office文件(Word、PPT)中的所有图片

    将Office文件转换为PDF文件,提取Office文件中的所有图片 1.Office系列---将Office文件(Word.PPT.Excel)转换为PDF文件 1.1 基于Office实现的解决方 ...

  2. Office系列(1)---将Office文件(Word、PPT、Excel)转换为PDF文件

    需求: 将Office文件作为文章并在网页上预览,主要为(Word.PPT.Excel)3种类型文件. 研究了一下,找到了两种解决方案 直接调用微软的在线预览功能实现(预览前提:预览资源必须可以直接通 ...

  3. php 将office文件(word/excel/ppt)转化为pdf(windows和linux只要安装对应组件应该就行)

    一.配置环境 (1)配置php.ini 添加:extension=php_com_dotnet.dll com.allow_dcom = true  // 去掉号,改为true 重启环境 (2) 安装 ...

  4. Aspose office (Excel,Word,PPT),PDF 在线预览

    前文: 做个备份,拿的是试用版的 Aspose,功能见标题 代码: /// <summary> /// Aspose office (Excel,Word,PPT),PDF 在线预览 // ...

  5. VBA Dumper v0.1.4.2, 提取office文档中的VBA代码,监查宏病毒恢复代码(演示版

    http://club.excelhome.net/thread-970051-1-1.html VBA Dumper 0.1.4.2更新,填补国内同类程序空白 此程序为演示版,可以在无office的 ...

  6. “PPT中如何插入和提取swf文件”的解决方案

    解决方案: 如何在PPT中插入swf文件: 1.依次单击Office按钮,Powerpoint选项,勾选“在功能区显示‘开发工具’选项卡”后,确定: 2.单击“开发工具”选项卡中的“其他控件”按钮,然 ...

  7. excel,word,ppt,pdf,swf 文件互相转换

    转自:  http://www.cnblogs.com/wolf-sun/p/3569960.html 引言 之前项目需要,查找了office文档在线预览的解决方案,顺便记录一下,方便以后查询. 方案 ...

  8. Office word 2013中直接调用MathType的方法

    Office word 2013中直接调用MathType的方法 | 浏览:4403 | 更新:2014-02-20 14:45 | 标签: word 使用Office word 2013的用户肯定早 ...

  9. VS编程中找不到Microsoft.Office.Core、Microsoft.Office.Interop.Word和VBIDE

    在使用vs2005. vs2008. vs2010 制作包含 word等office的应用程序时,有时找不到对Microsoft.Office.Core. Microsoft.Office.Inter ...

随机推荐

  1. Redux 初始化完整结构

    文件管理 目录文档 ★★★index.js★★★ ★★★app.js★★★ ★★★store->index.js★★★ ★★★actions->index.js★★★ ★★★store-& ...

  2. 2018-8-10-用-sim-卡加密保护资金

    title author date CreateTime categories 用 sim 卡加密保护资金 lindexi 2018-08-10 19:16:52 +0800 2018-2-13 17 ...

  3. P1065 汪老师的烟

    题目描述 汪老师有n根烟,他每吸完一根烟就把烟蒂保存起来,\(k(k>1)\) 个烟蒂可以换一个新的烟,那么 汪老师 最终能吸到多少根烟呢? 输入格式 每组测试数据一行包括两个整数 \(n,k( ...

  4. 如何通过命令行 msbuild 编译项目

    本文告诉大家如何通过 msbuild 编译一个项目,通过命令行编译可以输出更多的编译信息,可以用来调试自己写的编译相关方法,可以看到是哪个文件编译失败 在开始菜单可以找到 VisualStudio 的 ...

  5. H3C STP监控与维护

  6. css属性object-fit

    object-fit CSS 属性指定可替换元素的内容应该如何适应到其使用的高度和宽度确定的框. 属性值 contain:被替换的内容将被缩放,以在填充元素的内容框时保持其宽高比. 整个对象在填充盒子 ...

  7. js window.open 页面之间的通讯(不同源)

    一:a页面1:打开b页面let isB= window.open('b.html','b'); 2:a页面发送消息给b页面     isB.postMessage("dsddfsdf&quo ...

  8. WPF 分页控件Pager

    本文为伪原创原文为 NET未来之路的https://www.cnblogs.com/lonelyxmas/p/10641255.html 原文中,页码数量会不断增加,会将下一页的按钮顶出去 修改了一下 ...

  9. .NET Core开发的iNeuOS工业互联平台,升级四大特性:配置数据接口、图元绑定数据、预警配置和自定义菜单

    目       录 1.      概述... 2 2.      演示信息... 2 3.      iNeuView(Web组态)配置数据接口... 2 4.      iNeuView(Web组 ...

  10. Java 解析Exception信息

    最近的项目需要捕获系统抛出的异常,并将异常信息保存,记录以下解析Exception的方法. 异常详细信息 这里说的“异常详细信息”指的是平时打印到控制台的那种信息,如下图 获取方法: package ...