2008-09-30 136 views

回答

2

元文件是一個記錄GDI操作序列的文件。它具有可伸縮性,因爲捕捉了生成圖片的原始操作序列,因此可以縮放記錄的座標。

我認爲,在.NET中,您應該創建一個Metafile對象,使用Graphics.FromImage創建一個Graphics對象,然後執行繪製步驟。該文件在您繪製時自動更新。您可以在Graphics.AddMetafileComment的文檔中找到一個小樣本。

如果您確實想要在元文件中存儲位圖,請使用這些步驟,然後使用Graphics.DrawImage來繪製位圖。但是,縮放時將使用StretchBlt進行拉伸。

2

問題是:「是否有另一種方法將圖像保存到EMF/WMF?」不是「什麼是圖元文件」或「如何創建圖元文件」或「如何將圖元文件與圖形一起使用」。

我也去找答案這個問題「如何拯救EMF/WMF」 事實上,如果你使用:

Graphics grfx = CreateGraphics(); 
    MemoryStream ms = new MemoryStream(); 
    IntPtr ipHdc = grfx.GetHdc(); 

    Metafile mf = new Metafile(ms, ipHdc); 

    grfx.ReleaseHdc(ipHdc); 
    grfx.Dispose(); 
    grfx = Graphics.FromImage(mf); 

    grfx.FillEllipse(Brushes.Gray, 0, 0, 100, 100); 
    grfx.DrawEllipse(Pens.Black, 0, 0, 100, 100); 
    grfx.DrawArc(new Pen(Color.Red, 10), 20, 20, 60, 60, 30, 120); 
    grfx.Dispose(); 

    mf.Save(@"C:\file.emf", ImageFormat.Emf); 
    mf.Save(@"C:\file.png", ImageFormat.Png); 

在這兩種情況下的圖像保存爲PNG格式。這是我無法解決的問題:/

+0

請注意,您需要爲``Metafile`使用`System.Drawing.Imaging`併爲'MemoryStream`使用`System.IO`。 – 2012-07-24 09:24:48

9

如果我沒有記錯,它可以通過Metafile.GetHenhmetafile(),API GetEnhMetaFileBits()和Stream.Write()的組合來完成,如

[DllImport("gdi32")] static extern uint GetEnhMetaFileBits(IntPtr hemf, uint cbBuffer, byte[] lpbBuffer); 


IntPtr h = metafile.GetHenhMetafile(); 
int size = GetEnhMetaFileBits(h, 0, null); 
byte[] data = new byte[size]; 
GetEnhMetaFileBits(h, size, data); 
using (FileStream w = File.Create("out.emf")) { 
    w.Write(data, 0, size); 
} 
// TODO: I don't remember whether the handle needs to be closed, but I guess not. 

我想這就是我在解決問題時的方法。

+0

雖然它看起來應該工作,但我發現它輸出的是元文件的柵格化版本,而不是矢量GDI記錄。此外,您需要調用DeleteEnhMetaFile(h)並注意調用GetHenhMetaFile()會將圖元文件對象置於無效狀態。 – 2009-09-14 20:51:51

+0

完成後,您需要調用DeleteEnhMetafile(h),並通過GetHenhMetafile調用將Metafile對象置於無效狀態。 如果Metafile是一個基於柵格的圖元文件,這將給你一個基於.emf磁盤上的光柵。如果它是一個基於矢量的圖元文件,那麼你將在磁盤上得到一個基於.emf的矢量。通常調用metafile.Save(「文件名」,System.Drawing.Imaging.ImageFormat.Emf)會給你一個.png文件。 – 2009-09-14 20:59:01

2

erikkallen的答案是正確的。我想這從VB.NET,只好用2個不同的DllImports來得到它的工作:

<System.Runtime.InteropServices.DllImportAttribute("gdi32.dll", EntryPoint:="GetEnhMetaFileBits")> _ 
    Public Shared Function GetEnhMetaFileBits(<System.Runtime.InteropServices.InAttribute()> ByVal hEMF As System.IntPtr, ByVal nSize As UInteger, ByVal lpData As IntPtr) As UInteger 
End Function 

    <System.Runtime.InteropServices.DllImportAttribute("gdi32.dll", EntryPoint:="GetEnhMetaFileBits")> _ 
    Public Shared Function GetEnhMetaFileBits(<System.Runtime.InteropServices.InAttribute()> ByVal hEMF As System.IntPtr, ByVal nSize As UInteger, ByVal lpData() As Byte) As UInteger 
End Function 

第一個進口用於在第一次調用得到電動勢的大小。第二次導入得到實際的位。 或者你可以使用:

Dim h As IntPtr = mf.GetHenhmetafile() 
CopyEnhMetaFileW(h, FileName) 

這將emf位直接複製到指定的文件。

18

Image是一個抽象類:你想要做什麼取決於你是在處理一個Metafile還是一個Bitmap

使用GDI +創建圖像並將其保存爲EMF很簡單,Metafile。每邁克的post

var path = @"c:\foo.emf" 
var g = CreateGraphics(); // get a graphics object from your form, or wherever 
var img = new Metafile(path, g.GetHdc()); // file is created here 
var ig = Graphics.FromImage(img); 
// call drawing methods on ig, causing writes to the file 
ig.Dispose(); img.Dispose(); g.ReleaseHdc(); g.Dispose(); 

這是你想要做的大部分時間是什麼,因爲這是EMF是:保存矢量圖像GDI +繪圖命令的形式。

通過使用上述方法並調用ig.DrawImage(your_bitmap),您可以將Bitmap保存爲EMF文件,但請注意,這不會神奇地將您的柵格數據轉換爲矢量圖像。

+1

很好,我完全忽略了這種基於Metafile構造函數創建元文件的簡單方法。我必須承認,必須通過一個原始的HDC有點混亂,但它仍然有效。 – 2009-09-01 03:22:00

0

我正在尋找一種方法來將Metafile對象中的GDI指令保存爲EMF文件。韓的文章幫助我解決了這個問題。這是在我加入SOF之前。謝謝你,韓。這是什麼I tried

 
    [DllImport("gdi32.dll")] 
    static extern IntPtr CopyEnhMetaFile( // Copy EMF to file 
     IntPtr hemfSrc, // Handle to EMF 
     String lpszFile // File 
    ); 

    [DllImport("gdi32.dll")] 
    static extern int DeleteEnhMetaFile( // Delete EMF 
     IntPtr hemf // Handle to EMF 
    ); 

    // Code that creates the metafile 
    // Metafile metafile = ... 

    // Get a handle to the metafile 
    IntPtr iptrMetafileHandle = metafile.GetHenhmetafile(); 

    // Export metafile to an image file 
    CopyEnhMetaFile(
     iptrMetafileHandle, 
      "image.emf"); 

    // Delete the metafile from memory 
    DeleteEnhMetaFile(iptrMetafileHandle); 

0

它看起來對矢量與位圖有很多混淆。該線程中的所有代碼都會生成位圖(非矢量)文件 - 它不保留向量GDI調用。爲了證明這一點,請下載「EMF Parser」工具並檢查輸出文件:http://downloads.zdnet.com/abstract.aspx?docid=749645

這個問題已經引起許多開發人員考慮到痛苦。如果微軟能夠解決這個問題並且正確地支持他們自己的EMF格式,那肯定會很好。

+1

你錯了。例如,user120789的答案會創建矢量圖形。 – reinierpost 2013-05-14 14:35:41

2

您還需要關閉CopyEnhMetaFile處理程序:

IntPtr ptr2 = CopyEnhMetaFile(iptrMetafileHandle, "image.emf"); 
DeleteEnhMetaFile(ptr2); 

// Delete the metafile from memory 
DeleteEnhMetaFile(iptrMetafileHandle); 

否則,你無法刪除該文件,因爲它仍然使用的過程。

1

我建議避免這樣的extern和非託管cruft在一個託管的.NET應用程序。 相反,我建議更多的東西有點像在這個線程給出的託管解決方案:

Convert an image into WMF with .NET?

附:我正在回答這個老話題,因爲這是我找到的最好答案,但最終開發了一個託管解決方案,然後將我帶到上面的鏈接。所以,爲了節省那些時間,我想我會指出這一個。