C#生成EMF矢量圖形文件示例詳解
前言
公眾號上有網(wǎng)友詢問我如何生成 EMF 文件的問題:
本以為非常簡單,我快速給出了解決方案:
var bitmap = new Bitmap(640, 480); var g = Graphics.FromImage(bitmap); g.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 100, 100); bitmap.Save("MyIO.emf",ImageFormat.Emf);
結(jié)果,網(wǎng)友告訴我,這是錯誤的:
用編輯器查看文件內(nèi)容,發(fā)現(xiàn)實際生成的是PNG格式文件:
這是怎么回事呢?
原因
在官方文檔上找到這樣一段話:
當使用Save此方法將圖形圖像另存為Windows元文件格式 (WMF) 或增強的圖元文件格式 (EMF) 文件時,生成的文件將改為保存為可移植網(wǎng)絡圖形 (PNG) 文件。發(fā)生此行為是因為.NET Framework的GDI+組件沒有可用于將文件另存為 .wmf 或 .emf 文件的編碼器。
不理解這樣設計的原因,不支持應該拋出異常吧?!
實現(xiàn)
不過還好,從文檔上我們也找到了解決方案,那就是使用Metafile類。
可是在實現(xiàn)時,又踩了不少坑。
創(chuàng)建實例失敗
按照示例代碼,使用文件名創(chuàng)建實例:
var metafile = new Metafile("MyIO.emf");
結(jié)果報了個通用異常,完全沒有指導意義:
只好反編譯代碼查錯。
發(fā)現(xiàn),底層實現(xiàn)使用的GdipCreateMetafileFromFileAPI:
public Metafile(string filename) { Path.GetFullPath(filename); SafeNativeMethods.Gdip.CheckStatus(SafeNativeMethods.Gdip.GdipCreateMetafileFromFile(filename, out IntPtr metafile)); SetNativeImage(metafile); }
也就是說,參數(shù)必須是一個已存在的 EMF 文件名。
查看其他構(gòu)造函數(shù)的實現(xiàn),發(fā)現(xiàn)傳遞referenceHdc的構(gòu)造函數(shù)使用的是GdipRecordMetafileFileNameAPI:
public Metafile(string fileName, IntPtr referenceHdc, EmfType type, string? description) { Path.GetFullPath(fileName); SafeNativeMethods.Gdip.CheckStatus(SafeNativeMethods.Gdip.GdipRecordMetafileFileName(fileName, referenceHdc, type, IntPtr.Zero, MetafileFrameUnit.GdiCompatible, description, out IntPtr metafile)); SetNativeImage(metafile); }
也就是說,這個 API 可以創(chuàng)建 EMF 文件??磥砜梢杂?。
而referenceHdc可以使用Graphics.GetHdc()得到。
于是,實現(xiàn)代碼如下:
using (Graphics g1 = Graphics.FromHwnd(IntPtr.Zero)) { using (var metafile = new Metafile("MyIO.emf", g1.GetHdc())) { using (Graphics g2 = Graphics.FromImage(metafile)) { g2.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 100, 100); g2.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 200, 200); } } }
生成的確實是矢量圖形文件:
繪制位置錯誤
可以明顯看到,第一個My IO繪制的位置是錯誤的,繪制到了左上角,而不是(100, 100)。
再次查找構(gòu)造函數(shù),發(fā)現(xiàn)可以傳遞Rectangle參數(shù):
修改實現(xiàn)代碼如下:
using (Graphics g1 = Graphics.FromHwnd(IntPtr.Zero)) { using (var metafile = new Metafile("MyIO.emf", g1.GetHdc(), new Rectangle(0, 0, 300, 300), MetafileFrameUnit.Pixel)) { using (Graphics g2 = Graphics.FromImage(metafile)) { g2.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 100, 100); g2.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 200, 200); } } }
這次總算成功了:
結(jié)論
后來發(fā)現(xiàn),生成的圖片實際是375 x 375像素,這應該是因為我的顯示屬性設置了縮放的原因(375 / 300 = 1.25):
以上就是C#生成EMF矢量圖形文件示例詳解的詳細內(nèi)容,更多關于C#生成EMF矢量圖形文件的資料請關注腳本之家其它相關文章!
相關文章
C#判斷一個字符串是否是數(shù)字或者含有某個數(shù)字的方法
這篇文章主要介紹了C#判斷一個字符串是否是數(shù)字或者含有某個數(shù)字的方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2018-06-06C#請求http向網(wǎng)頁發(fā)送接收數(shù)據(jù)的方法
這篇文章主要為大家詳細介紹了C#請求http向網(wǎng)頁發(fā)送數(shù)據(jù)、網(wǎng)頁接收的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07用幾行C#代碼實現(xiàn)定時關機/重啟(超詳細!建議新手練習)
有很多的軟件都實現(xiàn)了自動關機這樣的功能,下面這篇文章主要給大家介紹了關于利用幾行C#代碼實現(xiàn)定時關機/重啟的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2022-12-12c#中SqlHelper封裝SqlDataReader的方法
這篇文章主要介紹了c#中SqlHelper封裝SqlDataReader的方法,涉及C#針對數(shù)據(jù)庫相關操作封裝與使用的技巧,需要的朋友可以參考下2015-05-05picturebox加載圖片的三種方法與網(wǎng)站驗證碼的抓取
這篇文章主要介紹了picturebox加載圖片的三種方法與網(wǎng)站驗證碼的抓取,需要的朋友可以參考下2015-03-03