回顾一下上文结尾的问题:如何给文档设置一个合适的封面图?其中一个解决方案就是,获取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. Python--day41--线程队列

    1,普通队列:queue.Queue(),先进先出 import queue q = queue.Queue() #队列 先进先出 q.put(1) q.put(2) q.put(3) q.put(4 ...

  2. Redux 认识之后进阶

    两个东西 action  状态 路由 以及嵌套路由 完整结构   进阶+源代码 源代码在我的 gitHub  存储库里面  https://github.com/Haisenan/Redux2.0

  3. java 打印流

    (只有两个,PrintWriter和PrintStream) 思考:如果现在要想完成一个字符串或者是boolean型或者是字符型的数据输出使用OutputStream是否方便? 肯定是不方便的,因为O ...

  4. linux主次编号

    字符设备通过文件系统中的名子来存取. 那些名子称为文件系统的特殊文件, 或者设备文 件, 或者文件系统的简单结点; 惯例上它们位于 /dev 目录. 字符驱动的特殊文件由使用 ls -l 的输出的第一 ...

  5. H3C DHCP服务器显示及维护

  6. linux测试 scullpipe 驱动

    我们已经见到了 scullpipe 驱动如何实现阻塞 I/O. 如果你想试一试, 这个驱动的源码 可在剩下的本书例子中找到. 阻塞 I/O 的动作可通过打开 2 个窗口见到. 第一个可运行 一个命令诸 ...

  7. 1119 机器人走方格 V2 (组合数学)

    M * N的方格,一个机器人从左上走到右下,只能向右或向下走.有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 10^9 + 7的结果.   Input 第1行,2个数M,N,中间用空格隔开 ...

  8. vue权限篇

    前言 在一个项目中,一些功能会涉及到重要的数据管理,为了确保数据的安全,我们会在项目中加入权限来限制每个用户的操作.作为前端,我们要做的是配合后端给到的权限数据,做页面上的各种各样的限制. 需求 因为 ...

  9. IdentityServer4 Resources

    原文地址 Resources 的定义 通常在系统中是顶一个需要保护的资源.这些资源可是用户的信息,比如身份信息或者邮箱地址,也可以是某些API的访问权限. Note: 可以通过C#的对象模型或者通过数 ...

  10. 【Docker】镜像基本操作

    1.镜像获取/生成 docker pull <image_name:tag> docker pull mysql:5.6 docker build -t <镜像名> <D ...