VSTO中Word转换Range为Image的方法
VSTO中Word转换Range为Image的方法
前言
VSTO是一套用于创建自定义Office应用程序的Visual Studio工具包,通过Interop提供的增强Office对象,可以对Word文档进行编程操作。Range是Word中执行操作的一个单元,可以理解成文档中一个选中的部分或者区域,针对这个选中部分,可以应用格式、修改文字和颜色等功能。出于各种业务的需求,常常需要将Word文档或者Word文档的一部分变成图片。本文对常见的Range转换为Image的方法进行了讨论和分析,并提出一些改良的地方。
剪贴板作为中介
原理很简单,就是将Range.Copy()到剪贴板中,剪贴板是windows进程间通信的一种方式,然后从剪贴板中获取metafile的信息还原成一个图片。
//原理示意
//source为Word.Range对象
//range.Copy()会将range中的内容复制到剪贴板中。
source.Copy();
//从剪贴板中获取metafile的数据
var metaData = GetMetaFileFromCicpBoard();
//根据metafile的信息构建出一个图片对象
Image image = GetImageFromMetaData(metaData);
这种方法在网上很常见,效果和手动在Word文档中复制一段文字,然后粘贴在<画图>软件上一样。然而在程序中,这个效果比较差。实际过程中,从剪贴板中获取数据,经常会失败,无法获取数据,推测是其他进程操作了剪贴板,数据丢失了。而且解析剪贴板的数据,需要引入的库已经很多年没维护了,经常出异常。
通过EnhMetaFileBits生成图片
这是最正常的方法了,直接通过API生成图片,效果好,速度快,图片的内容就是Word文档中的显示内容。
/// <summary>
/// 获取原生的range变为图片的方式
/// </summary>
/// <param name="range">选中部分</param>
/// <returns>图片,Image对象</returns>
public static Image GetRangeRealImage(Word.Range range)
{
if (range == null)
{
throw new Exception("range is empty");
}
var bits = (byte[])range.EnhMetaFileBits;
System.IO.MemoryStream ms = new System.IO.MemoryStream(bits);
var ret = Image.FromStream(ms);
return ret;
}
在实际使用过程中,发现这种方法也存在缺陷。在不足一页的range中,可以显示全部内容;在多页的range中,生成的图片只能显示第一页的内容。
获取多页Range的图片
为了解决这个问题,一个通常的思路是:既然可以获取一页的图片,把多页分成一页一页的,获取每一页的图片,然后合并起来,就是多页内容的图片了。
//伪代码
/// <summary>
/// 将range转换为完全的image图片
/// </summary>
/// <param name="range">选中部分</param>
/// <returns>图片</returns>
public Image RangeToImage(Word.Range range)
{
var ret = RangeImage.GetRangeRealImage(range);
//如果图片高度小于一页,直接返回
var limitHeight = 2000;
if (ret.Height < limitHeight)
{
return ret;
}
//可能大于一页
return GetBigRangePic(range);
}
从range中按页切割其实很困难,然而页是Word文档中的一个单位。可以把range复制到一个新文档B中,获取B文档的页数,获取B文档的每一页,然后就可以获取每一页的range部分了。
//伪代码
/// <summary>
/// 一种生成range大图的方法。word中range只能显示一页的区域,
/// range超过一页,也只能显示一页。
/// 将range复制到新文档中,拼接文档中
/// 每一页的图片,可以生成range的全图。
/// </summary>
/// <param name="source">需要生成图片的range</param>
/// <returns>生成好的image对象</returns>
public Image GetBigRangePic(Word.Range source)
{
Image ret = null;
var wordDoc = newTmpDoc();
//将source的内容复制的新文档中
addRangeToDoc(wordDoc, source);
//获取新文档的页数
var num = wordDoc.ComputeStatistics(Word.WdStatistic.wdStatisticPages);
//获取每一页的图片,并合并
for (int i= 1; i<=num; i++)
{
object page_num = i;
wordDoc.Application.Selection.GoTo(Word.WdGoToItem.wdGoToPage, Word.WdGoToDirection.wdGoToAbsolute, num, page_num);
var pageRange = wordDoc.Application.Selection.Bookmarks[@"\Page"].Range;
var pageImage = RangeImage.GetRangeRealImage(pageRange);
//第一页等于图片,第二页以后合并前面的部分
if (ret == null)
{
ret = pageImage;
}else
{
ret = MergeImageVertical(ret, pageImage);
}
}
//手动GC
GC.Collect();
//保证线程安全
lock (objlock)
{
//关闭文档
try
{
object saveChange = Word.WdSaveOptions.wdDoNotSaveChanges;
wordDoc.Close(ref saveChange, ref Nothing, ref Nothing);
}
catch (System.Runtime.InteropServices.COMException e)
{
Log.GetInstance().Error("close err:" + e.Message);
}
}
return ret;
}
这种方式成功获取了多页range的图片。其缺点在于是合并多页的图片,多页间的部分合并了看起来起来不自然;还有合并多页的图片,转换为多个Bitmap,然后开始合并,cpu负载高,消耗的内存大。
range替换为image的shape
将特定部分的range直接替换成一个图片,并删除原内容。打个比方,就像是魔术表演中,魔术师把手中的帽子变成兔子一样。
由于在Word中插入一个图片,必须是本地文件系统中的图片文件,range获取到的图片必须先存储在本地的临时目录,然后再插入到Word的相应位置中。
//处理流程
Range->图片->保存在本地,以png格式->插入到文档中->删除原先range的内容
//伪代码
//range为Word.Range对象
//获取图片
var image = RangeImage.GetRangeRealImage(range);
//保存图片到本地
var FileName = Config.GetInstance().Get("runtimePath") + System.IO.Path.DirectorySeparatorChar + "tmpTable.png";
image.Save(FileName, System.Drawing.Imaging.ImageFormat.Png);
//在原位置插入图片
object SaveWithDocument = true;
object LinkToFile = false;
var wordDoc = range.Document;
object Anchor = wordDoc.Range(range.Start);
var t = wordDoc.Application.ActiveDocument.InlineShapes.AddPicture(FileName, ref LinkToFile, ref SaveWithDocument, ref Anchor);
//删除原内容
range.Delete();
VSTO中Word转换Range为Image的方法的更多相关文章
- VSTO中Word的Range复制方式
VSTO中Word的Range复制方式 前言 VSTO是一套用于创建自定义Office应用程序的Visual Studio工具包,通过Interop提供的增强Office对象,可以对Word文档进行编 ...
- VSTO中Word的查找方式
VSTO中Word的查找方式 前言 使用C#在VSTO开发Word插件的过程,经常需要对文档中的内容进行查找和替换.在Word中进行文本的查找替换,和一般对纯文本的查找替换却不太一样.因为Word文档 ...
- JAVA中日期转换和日期计算的方法
日期的格式有很多形式,在使用过程中经常需要转换,下面是各种类型转换的使用例子以及日期计算方法的例子. 一.不同格式日期相互转换方法 public class TestDateConvertUtil { ...
- AS3中String转换成Boolean
AS3中, 对布尔值的转换, 规定所有的非空字符串都是true. 下面都不行: var f:Boolean = new Boolean(str); var f:Boolean = str as Boo ...
- C#将Word转换成PDF方法总结(基于Office和WPS两种方案)
有时候,我们需要在线上预览word文档,当然我们可以用NPOI抽出Word中的文字和表格,然后显示到网页上面,但是这样会丢失掉Word中原有的格式和图片.一个比较好的办法就是将word转换成pdf,然 ...
- word转换成HTML 以及IE不兼容问题
public static bool WordToHtml(string wordFileName, string htmlFileName) { try { Object oMissing = Sy ...
- 使用Java对接永中格式转换
永中格式转换服务基于永中DCS的文档转换能力,支持不同格式文件之间的高质量互转,可实现PDF文档与Word.Excel.PPT.图片的高质量互转,PDF文档转换完美保留原文档的版式,格式等,转换效果出 ...
- SQL Server中行列转换 Pivot UnPivot
SQL Server中行列转换 Pivot UnPivot PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PI ...
- awk中分隔符转换
awk中分隔符转换的问题(转) 在awk中明明用OFS重新设置了分隔符,为什么在输出的时候还是原样输出呢! 他是这么写的: echo 1,2,3,4 | awk 'BEGIN{FS=" ...
随机推荐
- MySQL 中 having 和 where 的区别
区别一: where 是数据从磁盘读入内存时候一条一条判断的 having 是将所有数据读入内存,在分组统计前,根据having的条件再将不符合条件的数据删除 区别二: having 子句可以使用字段 ...
- truffle 开发入门教程
1.安装nodejs 2.安装truffle:执行命令: npm install -g truffle 3.truffle init (可加项目名) 4.windows 要删除根目录中的 truff ...
- Senparc之OAuth原理
今天学习了网易云课堂的 盛派的微信开发课程之OAuth微信网页授权:OAuth原理,边听边来波笔记: 1.什么是OAuth? OAuth 你的接口提供给别人使用,你需要提供Oauth,可以让被人使用, ...
- ASP.NET Core Web App应用第三方Bootstrap模板
引言 作为后端开发来说,前端表示玩不转,我们一般会选择套用一些开源的Bootstrap 模板主题来进行前端设计.那如何套用呢?今天就简单创建一个ASP.NET Core Web MVC 模板项目为例, ...
- Java中的读写锁
一.读写锁 1.初识读写锁 a)Java中的锁——Lock和synchronized中介绍的ReentrantLock和synchronized基本上都是排它锁,意味着这些锁在同一时刻只允许一个线程进 ...
- proxy_pass根据path路径转发时的"/"问题记录
在nginx中配置proxy_pass时,如果是按照^~匹配路径时,要注意proxy_pass后的url最后的/.当加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理 ...
- [Swift]LeetCode169. 求众数 | Majority Element
Given an array of size n, find the majority element. The majority element is the element that appear ...
- Saiku设置展示table数据不隐藏空的行数据信息(二十六)
Saiku设置展示table数据不隐藏空的行数据信息 saiku有个 非空的字段 按钮,点击这个后,会自动的把空的行数据信息给隐藏掉,这里我们来设置一下让其行数据不隐藏,为空的就为空. 主要更改两个文 ...
- .NET Core 使用 HttpClient SSL 请求出错的解决办法
问题 使用 HTTP Client 请求 HTTPS 的 API 时出现 The certificate cannot be verified up to a trusted certificatio ...
- 如何创建测试程序调试nginx数据结构
如何创建测试程序调试nginx数据结构 由于在学习nginx的过程中遇到很多数据结构,往往我都想写一个程序来跑一下,看下到底返回什么.最开始想的方法是使用nginx make 完成之后的.o文件,做L ...