如何把Excel中的单元格等对象保存成图片

对于Excel中的很多对象,比如单元格(Cell),图形(shape),图表(chart)等等,有时需要将它们保存成一张图片。就像截图一样。 
最近做一个Excel相关的项目,项目中遇到一个很变态的需求, 需要对Excel中的一些对象进行拍图,比如,对一个单元格设置一些颜色之后拍图,或者对一个图表,报表拍成图片。经过比较曲折的经历,终于还是完成了。拿出来分享一下。 
要做Excel,首先当然是查看Excel的com对象模型。地址在这里: 
http://msdn.microsoft.com/en-us/library/bb149081(v=office.12).aspx 
这里说明一下: 
官方的Excel2010对象参考没有找到,点进去就是死循环,点来点去就是找不到,哪位神人找到了麻烦回复告知一下。  
Excel2003的对象模型,需要下下来安装,比较麻烦,我也是安装了之后才知道的,这里推荐大家就通过上面的网址查看Excel2007的模型就可以了。    实际上按照微软的兼容惯例,Excel2010和Excel2003的差别应该不大(是吗?)。 
然后是查看Range对象的成员,期待它有没有什么现成的方法就爽了:http://msdn.microsoft.com/en-us/library/bb225606(v=office.12).aspx 
查看了一圈,也没发现类似什么 ExportImage,SaveImage之类的方法。表示沮丧,不过也是情理之中。 
绝望之中发现了一个亮点,一个方法名字叫做CopyPicture。 看了一下方法说明,是要把对象当作图片拷到剪贴板里面。    呵呵,一个比较扭曲的想法诞生了,既然能拷到剪贴板里面,我再从剪贴板里面把图片抠出来不就行了吗。  
好,就这么定了,说干就干。 
…… 
此处省略200字(怎么创建excel的com对象, 怎么取到Range对象就不说了,不知道的自己查,也可以回复提问。) 
…… 
拿到Range对象之后。调用CopyPicture方法,需要两个参数。第一个参数是XlPictureAppearance枚举,1表示按照屏幕的样子拷贝,2表示按照打印时的样子拷贝。 第二个参数是XlCopyPictureFormat枚举,2表示拷贝成位图,-4147表示拷贝成矢量图片。 
于是乎,我写了大概类似如下的代码。

Range cell = excel.Activesheet.Cells[1,1];

cell.CopyPicture(1,2);

Bitmap image = Clipboard.GetImage() as Bitmap;

if(image != null)

{

//可以在这里为所欲为。

}

调试,运行,一切Ok,完全没问题,提交代码(期间还做了无数额外代码,此处不提。)。(嘿嘿,这种小事能难得到楼主吗,得意的笑。) 
然后24小时过去了,话说第二天到了。 
刚一上班,楼主就兴冲冲的发邮件告诉大家:恭喜大家,excel的拍图功能完成啦,大家赶快享用(是enjoy)吧。 
大家也都很配合,纷纷发来贺电:“楼主Nb啊”之类的。 
楼主的虚荣心得到了极大的满足,表示很开心。沉浸在自我陶醉之中。。。 
不多时,同组一MM惊呼楼主的名字,“楼主,楼主,你快来看看吧,你的拍图功能真的太……”。 在最后还有两个字没说出来的时候,楼主已经飞奔到MM的身边。话说此MM那可真是。。(嗯,先不说吧),“太给力吗”,楼主很自信的补充了剩下的几个字。 MM手指屏幕,“你的拍图怎么崩掉了。”, 果然,屏幕上一个NullReferenceException嚣张的躺在屏幕中央。 楼主果断调试代码,跟踪发现,确实是拍图出了问题,上面的Clipboard.GetImage() 返回了null。 怎么会呢, 楼主又反复运行了几次,结果一样,都是返回null。 楼主表示鸭梨很大。 
不过,鸭梨归鸭梨,楼主是个不轻易服输的人,口头禅是:我就不信这个邪了。 这次也是,楼主一边说着口头禅,一边继续跟踪。 
首先当然是要看看剪贴板的数据,看拷贝成功了没, 
Clipboard.GetDataObject().GetFormats() 方法返回: 
  [0]: "EnhancedMetafile" 
    [1]: "MetaFilePict" 
    [2]: "Link" 
看样子,应该是拷出来了。然后楼主通过这几个format来get数据,发现还是不成功。  这就奇怪了。 
楼主很受打击,回到座位上继续调试。 
相同的代码,在楼主的机器上就是好好的,为什么在MM的机器上就是null呢。 
楼主在自己的机器上再次查看剪贴板数据。 
用Clipboard.GetDataObject().GetFormats() 方法返回: 
[0]: "System.Drawing.Bitmap" 
    [1]: "Bitmap" 
    [2]: "DeviceIndependentBitmap" 
    [3]: "Format17" 
    [4]: "Link" 
咦,怎么和上面的不一样呢。楼主很果断的发现,楼主的机器上安装的是Excel2010,而mm的机器上安装的是Excel2007. 原来是它们考出来的数据不一样。 
果断Google之。  于是,经过若干次失败和跳转,楼主来到这里:http://support.microsoft.com/kb/323530/en-us/ 
方才恍然大悟,这里的大概意思是说,由于.Net的一些限制,一些旧的程序(比如这里遇到的Excel2007)复制到剪贴板的数据可能不可用,需要通过本地Api来使用。 我去。。。 msdn上也没见半个字的提醒。 
楼主是个比较勤快的人,知道了这个,那还不赶快动手。 
于是楼主写下了大概类似如下的代码:

IntPtr hwnd = excel.Hwnd;

try

{

                 if (OpenClipboard(hwnd))

                 {

                     IntPtr data = GetClipboardData(14); // CF_ENHMETAFILE      14

                     if (data != IntPtr.Zero)

                     {

                         using (Metafile mf = new Metafile(data, true))

                         {

//这里有点多余,不过因为需要的是bitmap格式。就忍了。

                             Bitmap b = new Bitmap(mf);

                             return b;

                         }

                     }

                 }

             }

             finally

             {

                 CloseClipboard();

             }

[DllImport("User32.dll")]         [return: MarshalAs(UnmanagedType.Bool)]         public static extern bool OpenClipboard(IntPtr hWndNewOwner);

[DllImport("User32.dll")]         [return: MarshalAs(UnmanagedType.Bool)]         public static extern bool CloseClipboard();     [DllImport("User32.dll")]         public static extern IntPtr GetClipboardData(System.UInt32 uFormat);

调试,运行,成功。呵呵,又是得意的笑。提交代码(期间省略若干额外代码)。 
楼主又一次兴冲冲的发邮件给大家:excel的拍图可以用啦,大家快来享用吧。 
然后,大家很配合纷纷发来贺电,然后。。。。 
然后。。。。 
然后什么,然后没了,很抱歉让大家失望了,这次没出问题。搞定。得意的笑。 
总结一下吧: 
1. 第一点要注意的是,Excel2007和Excel2010的拷贝数据格式不一样,要特别注意。 
2. 很显然,excel里面凡是带有CopyPIcture方法的对象,都可以这样拍图。 粗略的看了一下,很多对象 都有这个方法,Range,Shape,Chart等等。 
3. 另外,对于Chart对象,它还有一个Export方法,可以直接导出成图片。 
4. 辛勤的楼主把上面的方法稍稍包装了一个Win32ClipboardHelper, 使用其中的GetImage传入excel的hwnd,就可以从剪贴板里面取出图片了。  上传到附件中,供大家享用。 
5. 最后,友情提醒,由于某些原因,上文中出现的代码都是示意代码,与真实项目无关,也不保证上面的代码能编译通过,大家领会精神,不可较真。

在以上如何把Excel中的单元格等对象保存成图片的学习中,我们又增加了对Excel使用的认识。如果在项目中需要集成Excel的功能,还可以利用一下开发工具。SpreadJS 是企业级JavaScript电子表格控件,能将电子表格、数据可视化及计算功能集成在JavaScript Web应用程序中,能创建计算器、动态交互式仪表盘和样式丰富的报表。

源码下载

Win32ClipboardHelper.zip

时间: 2024-09-30 10:29:34

如何把Excel中的单元格等对象保存成图片的相关文章

C#中怎么在EXCEL中的单元格中画斜线啊 ??

Code Snippet 做法: 1,先添加引用COM,找 Excel 2,using Excel = Microsoft.Office.Interop.Excel; 3, 代码 private Excel.Application m_objExcel = null;        private Excel.Workbooks m_objBooks = null;        private Excel._Workbook m_objBook = null;        private E

利用VBS合并Excel中相同单元格

假如有一份这样的表格 你需要把不同行上相同的单元格进行合并,实现下面的效果 可以通过以下步骤用VBS来实现 1. 首先对表格进行排序,排序的这一列也是单元格合并时所参照的列,通常是学号或者ID列等 2. 然后在当前Excel表格中按Alt + F11,调出VBS编辑器,贴入以下代码 Sub mergerow()    'Declare variables    Dim lRow As Double      'Last row    Dim sRow As Double      'Curren

读取Excel文件中的单元格的内容和颜色

读取Excel文件中的单元格的内容和颜色 先创建一个Excel文件,在A1和A2中随意输入内容,设置A1的字体颜色为红色,A2的背景为黄色.需要 using Excel = Microsoft.Office.Interop.Excel;或者using Microsoft.Excel; string file = @"E:\test.xls"; //测试文件 Excel.Application excel = null; Excel.Workbook wkb = null; try {

[从产品角度学excel 04]-单元格的“衣服”

忘记发这里了..补发一下 这是<从产品角度学EXCEL>系列——单元格篇. 前言请看: 0 为什么要关注EXCEL的本质 1 excel是怎样运作的 2 EXCEL里的树形结构 3 单元格的秘密(文本/数字篇) 或者你可以去微信公众号@尾巴说数 获得连载目录. 本文仅由尾巴本人发布于特定网站.不接受任何无授权转载,如需转载,请先联系我,非常感谢. 抱歉之前因为有各种事情,一个多月没更新了,从今天开始恢复更新. 在前一章节里,我们通过对excel xml代码的阅读,发现在excel单元格里,文本

带复杂表头合并单元格的HtmlTable转换成DataTable并导出Excel(转)

步骤: 一.前台JS取HtmlTable数据,根据设定的分隔符把数据拼接起来 <!--导出Excel--> <script type="text/javascript"> //导出Excel function exportExcel() { var data = ""; $("#divRptTable").find("table").find("tr").each(function

基于.NET的Excel开发:单元格区域的操作(读取、赋值、边框和格式)

引用 using Excel = Microsoft.Office.Interop.Excel; 定义 1 Excel.ApplicationClass app; 2 Excel.Workbooks books; 3 Excel.Workbook book; 4 Excel.Sheets sheets; 5 Excel.Worksheet sheet; 6 Excel.Range m_objRange; 7 object missing = System.Reflection.Missing.V

转:jxl导出excel(合并单元格)

Demo 代码如下: 1 import java.io.*; 2 import jxl.*; 3 import jxl.format.UnderlineStyle; 4 import jxl.write.*; 5 public class CreateXLS { 6 public static void main(String args[]) { 7 try { 8 //打开文件 9 WritableWorkbook book= Workbook.createWorkbook(new File(

gridview中的单元格弹出一个窗口

网格中的单元格弹出一个窗口 $(document).ready(function(){ var s=$('#grdTest_Div'); var tr=$('#grdTest_Div').children().children().children().children(); var grid = document.all.grdTest; tr.each(function(i,j){ if(i!=0&&i!=tr.length) { $('td',j).eq(3).click(funct

如何实时获取DBGrid 中当前单元格输入的内容?

如何获取DBGrid 中当前单元格输入的内容? 还没输入完成,我想实时获取 Cell中的内容,以便作其他处理, 用什么事件呢? 所以Field的Onchange事件是没用的. 这个问题简单啊,每输入1个数据的后就提交(并不是提交到数据库,还是在编辑状态),那么用DataSet就可以取值了 用DBGrid的KeyUp事件: procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word;   Shift: TShiftState); beg