C#生成EMF矢量圖形文件示例詳解
前言
公眾號(hào)上有網(wǎng)友詢問我如何生成 EMF 文件的問題:

本以為非常簡(jiǎn)單,我快速給出了解決方案:
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)友告訴我,這是錯(cuò)誤的:

用編輯器查看文件內(nèi)容,發(fā)現(xiàn)實(shí)際生成的是PNG格式文件:

這是怎么回事呢?
原因
在官方文檔上找到這樣一段話:
當(dāng)使用Save此方法將圖形圖像另存為Windows元文件格式 (WMF) 或增強(qiáng)的圖元文件格式 (EMF) 文件時(shí),生成的文件將改為保存為可移植網(wǎng)絡(luò)圖形 (PNG) 文件。發(fā)生此行為是因?yàn)?NET Framework的GDI+組件沒有可用于將文件另存為 .wmf 或 .emf 文件的編碼器。
不理解這樣設(shè)計(jì)的原因,不支持應(yīng)該拋出異常吧?!
實(shí)現(xiàn)
不過還好,從文檔上我們也找到了解決方案,那就是使用Metafile類。
可是在實(shí)現(xiàn)時(shí),又踩了不少坑。
創(chuàng)建實(shí)例失敗
按照示例代碼,使用文件名創(chuàng)建實(shí)例:
var metafile = new Metafile("MyIO.emf");結(jié)果報(bào)了個(gè)通用異常,完全沒有指導(dǎo)意義:

只好反編譯代碼查錯(cuò)。
發(fā)現(xiàn),底層實(shí)現(xiàn)使用的GdipCreateMetafileFromFileAPI:
public Metafile(string filename)
{
Path.GetFullPath(filename);
SafeNativeMethods.Gdip.CheckStatus(SafeNativeMethods.Gdip.GdipCreateMetafileFromFile(filename, out IntPtr metafile));
SetNativeImage(metafile);
}
也就是說,參數(shù)必須是一個(gè)已存在的 EMF 文件名。
查看其他構(gòu)造函數(shù)的實(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);
}
也就是說,這個(gè) API 可以創(chuàng)建 EMF 文件??磥砜梢杂谩?/p>
而referenceHdc可以使用Graphics.GetHdc()得到。
于是,實(shí)現(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);
}
}
}生成的確實(shí)是矢量圖形文件:

繪制位置錯(cuò)誤
可以明顯看到,第一個(gè)My IO繪制的位置是錯(cuò)誤的,繪制到了左上角,而不是(100, 100)。
再次查找構(gòu)造函數(shù),發(fā)現(xiàn)可以傳遞Rectangle參數(shù):

修改實(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),生成的圖片實(shí)際是375 x 375像素,這應(yīng)該是因?yàn)槲业娘@示屬性設(shè)置了縮放的原因(375 / 300 = 1.25):

以上就是C#生成EMF矢量圖形文件示例詳解的詳細(xì)內(nèi)容,更多關(guān)于C#生成EMF矢量圖形文件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#使用Twain協(xié)議實(shí)現(xiàn)掃描儀連續(xù)掃描功能
這篇文章主要介紹了C#使用Twain協(xié)議實(shí)現(xiàn)掃描儀連續(xù)掃描,只需一行代碼,就可實(shí)現(xiàn)一次掃描多張,且不需要更改掃描儀的任何設(shè)置,需要的朋友可以參考下2022-01-01
C# 無邊框窗體之窗體移動(dòng)實(shí)現(xiàn)代碼
這篇文章介紹了C# 無邊框窗體之窗體移動(dòng)實(shí)現(xiàn)代碼,有需要的朋友可以參考一下2013-10-10
深入多線程之:內(nèi)存柵欄與volatile關(guān)鍵字的使用分析
本篇文章對(duì)內(nèi)存柵欄與volatile關(guān)鍵字的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
使用C#和Jieba.NET實(shí)現(xiàn)中英文混合文本關(guān)鍵詞的提取功能
Jieba.NET?是一個(gè)在?C#?中實(shí)現(xiàn)的分詞庫,它基于?Java?的?jieba?分詞庫,并進(jìn)行了?C#?語言的移植,Jieba?是一個(gè)高效的中文分詞工具,能夠處理全模式、精確模式以及搜索引擎模式,本文給大家介紹了如何使用C#和Jieba.NET實(shí)現(xiàn)中英文混合文本關(guān)鍵詞的提取功能2025-03-03
C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已安裝軟件變化的方法
這篇文章主要介紹了C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已安裝軟件變化的方法,涉及C#針對(duì)注冊(cè)表的讀取與監(jiān)控技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-08-08
c#使用FreeSql生產(chǎn)環(huán)境時(shí)自動(dòng)升級(jí)備份數(shù)據(jù)庫
使用FreeSql,包含所有的ORM數(shù)據(jù)庫,都會(huì)存在這樣的問題。在codefirst模式下,根據(jù)代碼自動(dòng)更新數(shù)據(jù)庫,都建議不要在生產(chǎn)環(huán)境使用。因?yàn)槿菀讈G失數(shù)據(jù),本文提供一種自動(dòng)更新數(shù)據(jù)庫的解決的思路:在判斷需要升級(jí)時(shí),才自動(dòng)升級(jí),同時(shí)升級(jí)前先備份數(shù)據(jù)庫2021-06-06
簡(jiǎn)單了解C#設(shè)計(jì)模式編程中的橋接模式
這篇文章主要介紹了C#設(shè)計(jì)模式編程中的橋接模式,橋接模式經(jīng)常應(yīng)用于解耦邏輯層與數(shù)據(jù)操作層,需要的朋友可以參考下2016-02-02

