Office系列(2)---提取Office文件(Word、PPT)中的所有图片
回顾一下上文结尾的问题:如何给文档设置一个合适的封面图?其中一个解决方案就是,获取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();
}
上面代码中有几个需要注意的地方:
Slides
和Shapes
都是从1开始遍历的Clipboard
对象在System.Windows.Forms.dll
中- PPT文件中图片有两种存在的方式,单独为形状的图片(
shape.Type == MsoShapeType.msoPicture
)和作为形状背景的图片(shape.Fill.Type == MsoFillType.msoFillPicture
) - 使用
shape.Copy()
来复制形状到剪切板,而不能直接通过Clipboard.SetDataObject(shape)
。
简单介绍下上面代码的实现思路,就好像用Office软件打开了PPT文件,然后选择包含图片的形状,Ctrl + C
然后Ctrl + V
到本地。有兴趣的同学可以尝试下,在PPT中复制图片,然后在微信对话框中粘贴。
当然这种做法有着很大的缺陷:
- 图片不全,通过上面的判定方式获取到的只是一部分的图片并没有把所有文件都保存到本地
- 图片异常,如果尝试过,将PPT中图片复制到微信里,你会发现它是把整个形状生成了一张图片。比如在一个文本框中输入文字,然后再加上图片背景,最后复制到出来的就是包含了文字的一张图片。
- 图片模糊,复制出来的图片分辨率有限,不再是原来的图片分辨率了。
总而言之,该解决方案仅供学习参考,实际应用还是不合适的!!!
基于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)中的所有图片的更多相关文章
- Office系列---将Office文件(Word、PPT、Excel)转换为PDF文件,提取Office文件(Word、PPT)中的所有图片
将Office文件转换为PDF文件,提取Office文件中的所有图片 1.Office系列---将Office文件(Word.PPT.Excel)转换为PDF文件 1.1 基于Office实现的解决方 ...
- Office系列(1)---将Office文件(Word、PPT、Excel)转换为PDF文件
需求: 将Office文件作为文章并在网页上预览,主要为(Word.PPT.Excel)3种类型文件. 研究了一下,找到了两种解决方案 直接调用微软的在线预览功能实现(预览前提:预览资源必须可以直接通 ...
- php 将office文件(word/excel/ppt)转化为pdf(windows和linux只要安装对应组件应该就行)
一.配置环境 (1)配置php.ini 添加:extension=php_com_dotnet.dll com.allow_dcom = true // 去掉号,改为true 重启环境 (2) 安装 ...
- Aspose office (Excel,Word,PPT),PDF 在线预览
前文: 做个备份,拿的是试用版的 Aspose,功能见标题 代码: /// <summary> /// Aspose office (Excel,Word,PPT),PDF 在线预览 // ...
- VBA Dumper v0.1.4.2, 提取office文档中的VBA代码,监查宏病毒恢复代码(演示版
http://club.excelhome.net/thread-970051-1-1.html VBA Dumper 0.1.4.2更新,填补国内同类程序空白 此程序为演示版,可以在无office的 ...
- “PPT中如何插入和提取swf文件”的解决方案
解决方案: 如何在PPT中插入swf文件: 1.依次单击Office按钮,Powerpoint选项,勾选“在功能区显示‘开发工具’选项卡”后,确定: 2.单击“开发工具”选项卡中的“其他控件”按钮,然 ...
- excel,word,ppt,pdf,swf 文件互相转换
转自: http://www.cnblogs.com/wolf-sun/p/3569960.html 引言 之前项目需要,查找了office文档在线预览的解决方案,顺便记录一下,方便以后查询. 方案 ...
- Office word 2013中直接调用MathType的方法
Office word 2013中直接调用MathType的方法 | 浏览:4403 | 更新:2014-02-20 14:45 | 标签: word 使用Office word 2013的用户肯定早 ...
- VS编程中找不到Microsoft.Office.Core、Microsoft.Office.Interop.Word和VBIDE
在使用vs2005. vs2008. vs2010 制作包含 word等office的应用程序时,有时找不到对Microsoft.Office.Core. Microsoft.Office.Inter ...
随机推荐
- Python--day61--Django中的app
- python的if判断
if 判断条件的时候,如果是多个条件一起进行判断,那么就需要逻辑运算符 并且-----------and 或者-----------or 非(取反)----not if 条件1 and 条件2 ...
- P1003 电影票价
题目描述 已知一位小朋友的电影票价是10元,请问 \(n\) 位小朋友的总票价是多少? 输入格式 输入一个整数 \(n(1 \le n \le 1000)\) , 用于表示小朋友的数量. 输出格式 输 ...
- 【21.58%】【codeforces 746D】Green and Black Tea
time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...
- maven仓库总结,maven私服搭建,批量mvn eclipse:eclipse
配置pom.xml依赖包时在这里找包的描述: http://search.maven.org/#browse 以java为根目录. mvn archtype:generate -DgroupId=zt ...
- LightOJ - 1287 Where to Run (期望dp+记忆化)
题面: Last night you robbed a bank but couldn't escape and when you just got outside today, the police ...
- python调用另一个文件中的代码,pycharm环境下:同文件夹下文件(.py)之间的调用,出现红线问题
如何调用另一个python文件中的代码无论我们选择用何种语言进行程序设计时,都不可能只有一个文件(除了“hello world”),通常情况下,我们都需要在一个文件中调用另外一个文件的函数呀数据等等, ...
- Trie 树的一些题
Trie 树的一些题 牛客练习赛11 假的字符串 (Trie树+拓扑找环) 链接:https://ac.nowcoder.com/acm/problem/15049 来源:牛客网 给定n个字符串,互不 ...
- python类方法、类属性和静态方法
class Game(object): #类属性 num = 0 #实例方法 def __init__(self): #实例属性 self.name = "laowang" #类方 ...
- TCP/IP||动态选路
1.动态选路 动态选路协议用于路由器之间的通信,当相邻路由器之间进行通信,已告知对方每个路由器当前所连接的网络,就产生了动态选路,在Internet之间采用了许多不同的选路协议,Internet是以一 ...