最近做一個(gè)Excel相關(guān)的項(xiàng)目,項(xiàng)目中遇到一個(gè)很變態(tài)的需求, 需要對(duì)Excel中的一些對(duì)象進(jìn)行拍圖,比如,對(duì)一個(gè)單元格設(shè)置一些顏色之后拍圖,或者對(duì)一個(gè)圖表,報(bào)表拍成圖片。經(jīng)過(guò)比較曲折的經(jīng)歷,終于還是完成了。拿出來(lái)分享一下。
要做Excel,首先當(dāng)然是查看Excel的com對(duì)象模型。地址在這里:
http://msdn.microsoft.com/en-us/library/bb149081(v=office.12).aspx
這里說(shuō)明一下:
官方的Excel2010對(duì)象參考沒(méi)有找到,點(diǎn)進(jìn)去就是死循環(huán),點(diǎn)來(lái)點(diǎn)去就是找不到,哪位神人找到了麻煩回復(fù)告知一下。
Excel2003的對(duì)象模型,需要下下來(lái)安裝,比較麻煩,我也是安裝了之后才知道的,這里推薦大家就通過(guò)上面的網(wǎng)址查看Excel2007的模型就可以了。 實(shí)際上按照微軟的兼容慣例,Excel2010和Excel2003的差別應(yīng)該不大(是嗎?)。
然后是查看Range對(duì)象的成員,期待它有沒(méi)有什么現(xiàn)成的方法就爽了:http://msdn.microsoft.com/en-us/library/bb225606(v=office.12).aspx
查看了一圈,也沒(méi)發(fā)現(xiàn)類似什么 ExportImage,SaveImage之類的方法。表示沮喪,不過(guò)也是情理之中。
絕望之中發(fā)現(xiàn)了一個(gè)亮點(diǎn),一個(gè)方法名字叫做CopyPicture。 看了一下方法說(shuō)明,是要把對(duì)象當(dāng)作圖片拷到剪貼板里面。 呵呵,一個(gè)比較扭曲的想法誕生了,既然能拷到剪貼板里面,我再?gòu)募糍N板里面把圖片摳出來(lái)不就行了嗎。
好,就這么定了,說(shuō)干就干。
……
此處省略200字(怎么創(chuàng)建excel的com對(duì)象, 怎么取到Range對(duì)象就不說(shuō)了,不知道的自己查,也可以回復(fù)提問(wèn)。)
……
拿到Range對(duì)象之后。調(diào)用CopyPicture方法,需要兩個(gè)參數(shù)。第一個(gè)參數(shù)是XlPictureAppearance枚舉,1表示按照屏幕的樣子拷貝,2表示按照打印時(shí)的樣子拷貝。 第二個(gè)參數(shù)是XlCopyPictureFormat枚舉,2表示拷貝成位圖,-4147表示拷貝成矢量圖片。
于是乎,我寫了大概類似如下的代碼。
Range cell = excel.Activesheet.Cells[1,1];
cell.CopyPicture(1,2);
Bitmap image = Clipboard.GetImage() as Bitmap;
if(image != null)
{
//可以在這里為所欲為。
}
調(diào)試,運(yùn)行,一切Ok,完全沒(méi)問(wèn)題,提交代碼(期間還做了無(wú)數(shù)額外代碼,此處不提。)。(嘿嘿,這種小事能難得到樓主嗎,得意的笑。)
然后24小時(shí)過(guò)去了,話說(shuō)第二天到了。
剛一上班,樓主就興沖沖的發(fā)郵件告訴大家:恭喜大家,excel的拍圖功能完成啦,大家趕快享用(是enjoy)吧。
大家也都很配合,紛紛發(fā)來(lái)賀電:“樓主Nb啊”之類的。
樓主的虛榮心得到了極大的滿足,表示很開(kāi)心。沉浸在自我陶醉之中。。。
不多時(shí),同組一MM驚呼樓主的名字,“樓主,樓主,你快來(lái)看看吧,你的拍圖功能真的太……”。 在最后還有兩個(gè)字沒(méi)說(shuō)出來(lái)的時(shí)候,樓主已經(jīng)飛奔到MM的身邊。話說(shuō)此MM那可真是。。(嗯,先不說(shuō)吧),“太給力嗎”,樓主很自信的補(bǔ)充了剩下的幾個(gè)字。 MM手指屏幕,“你的拍圖怎么崩掉了!, 果然,屏幕上一個(gè)NullReferenceException囂張的躺在屏幕中央。 樓主果斷調(diào)試代碼,跟蹤發(fā)現(xiàn),確實(shí)是拍圖出了問(wèn)題,上面的Clipboard.GetImage() 返回了null。 怎么會(huì)呢, 樓主又反復(fù)運(yùn)行了幾次,結(jié)果一樣,都是返回null。 樓主表示鴨梨很大。
不過(guò),鴨梨歸鴨梨,樓主是個(gè)不輕易服輸?shù)娜,口頭禪是:我就不信這個(gè)邪了。 這次也是,樓主一邊說(shuō)著口頭禪,一邊繼續(xù)跟蹤。
首先當(dāng)然是要看看剪貼板的數(shù)據(jù),看拷貝成功了沒(méi),
Clipboard.GetDataObject().GetFormats() 方法返回:
[0]: "EnhancedMetafile"
[1]: "MetaFilePict"
[2]: "Link"
看樣子,應(yīng)該是拷出來(lái)了。然后樓主通過(guò)這幾個(gè)format來(lái)get數(shù)據(jù),發(fā)現(xiàn)還是不成功。 這就奇怪了。
樓主很受打擊,回到座位上繼續(xù)調(diào)試。
相同的代碼,在樓主的機(jī)器上就是好好的,為什么在MM的機(jī)器上就是null呢。
樓主在自己的機(jī)器上再次查看剪貼板數(shù)據(jù)。
用Clipboard.GetDataObject().GetFormats() 方法返回:
[0]: "System.Drawing.Bitmap"
[1]: "Bitmap"
[2]: "DeviceIndependentBitmap"
[3]: "Format17"
[4]: "Link"
咦,怎么和上面的不一樣呢。樓主很果斷的發(fā)現(xiàn),樓主的機(jī)器上安裝的是Excel2010,而mm的機(jī)器上安裝的是Excel2007. 原來(lái)是它們考出來(lái)的數(shù)據(jù)不一樣。
果斷Google之。 于是,經(jīng)過(guò)若干次失敗和跳轉(zhuǎn),樓主來(lái)到這里:http://support.microsoft.com/kb/323530/en-us/
方才恍然大悟,這里的大概意思是說(shuō),由于.Net的一些限制,一些舊的程序(比如這里遇到的Excel2007)復(fù)制到剪貼板的數(shù)據(jù)可能不可用,需要通過(guò)本地Api來(lái)使用。 我去。。。 msdn上也沒(méi)見(jiàn)半個(gè)字的提醒。
樓主是個(gè)比較勤快的人,知道了這個(gè),那還不趕快動(dòng)手。
于是樓主寫下了大概類似如下的代碼:
try
if (OpenClipboard(hwnd))
{ IntPtr data = GetClipboardData(14); // CF_ENHMETAFILE 14
if (data != IntPtr.Zero)
{
using (Metafile mf = new Metafile(data, true))
{
//這里有點(diǎn)多余,不過(guò)因?yàn)樾枰氖莃itmap格式。就忍了。
Bitmap b = new Bitmap(mf);
return b;
}
}
}
}
finally
{
}
[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);
調(diào)試,運(yùn)行,成功。呵呵,又是得意的笑。提交代碼(期間省略若干額外代碼)。
樓主又一次興沖沖的發(fā)郵件給大家:excel的拍圖可以用啦,大家快來(lái)享用吧。
然后,大家很配合紛紛發(fā)來(lái)賀電,然后。。。。
然后。。。。
然后什么,然后沒(méi)了,很抱歉讓大家失望了,這次沒(méi)出問(wèn)題。搞定。得意的笑。
總結(jié)一下吧:
1. 第一點(diǎn)要注意的是,Excel2007和Excel2010的拷貝數(shù)據(jù)格式不一樣,要特別注意。
2. 很顯然,excel里面凡是帶有CopyPIcture方法的對(duì)象,都可以這樣拍圖。 粗略的看了一下,很多對(duì)象 都有這個(gè)方法,Range,Shape,Chart等等。
3. 另外,對(duì)于Chart對(duì)象,它還有一個(gè)Export方法,可以直接導(dǎo)出成圖片。
4. 辛勤的樓主把上面的方法稍稍包裝了一個(gè)Win32ClipboardHelper, 使用其中的GetImage傳入excel的hwnd,就可以從剪貼板里面取出圖片了。 上傳到附件中,供大家享用。
5. 最后,友情提醒,由于某些原因,上文中出現(xiàn)的代碼都是示意代碼,與真實(shí)項(xiàng)目無(wú)關(guān),也不保證上面的代碼能編譯通過(guò),大家領(lǐng)會(huì)精神,不可較真。