2011-03-11 115 views
3

有很多的WMF轉換成像一個位圖的例子: Reliable .wmf/wmf to Pixel based image conversion使用.NET將圖像轉換爲WMF?

但我需要反向操作。我不尋找一個矢量化器。我只想在wmf文件中嵌入一張圖片,而不必擔心wmf格式的位和字節。我最好在C#中使用.NET的解決方案。

我首先認爲這將做的工作:

using (Image img = Image.FromFile (path)) { 
    img.Save (myStream, System.Drawing.Imaging.ImageFormat.Wmf); 
} 

但這種抱怨在運行編碼器爲空。在哪裏/如何構建這樣的編碼器?我不需要一個複雜的,只是一個包裝圖像到一個WMF。對WMF中支持的格式有一些要求嗎?我想png和bmp都支持,但是gif也支持?

回答

3

here

當您使用Save方法一 圖形圖像保存爲Windows圖元文件 格式(WMF)或增強型圖元文件 格式(EMF)文件,生成的文件 保存作爲便攜式網絡 圖形(PNG)文件。因爲.NET Framework的GDI + 組件的確如此 行爲發生 沒有編碼器,您可以使用 將文件保存爲.wmf或.emf文件。

但我猜你已經有了那麼遠:)

Here有人把一個位圖一個FileStream。

metafileStream = MakeMetafileStream(gdiBitmap); 

與MakeMetafileStream()是:

private static MemoryStream MakeMetafileStream(Bitmap image) 
{ 
    Graphics graphics = null; 
    Metafile metafile= null; 
    var stream = new MemoryStream(); 
    try 
    { 
    using (graphics = Graphics.FromImage(image)) 
    { 
     var hdc = graphics.GetHdc(); 
     metafile= new Metafile(stream, hdc); 
     graphics.ReleaseHdc(hdc); 
    } 
    using (graphics = Graphics.FromImage(metafile)) 
    { graphics.DrawImage(image, 0, 0); } 
    } 
    finally 
    { 
    if (graphics != null) 
    { graphics.Dispose(); } 
    if (metafile!= null) 
    { metafile.Dispose(); } 
    } 
    return stream; 
} 

有趣的東西。 但至於編碼器的事...

Here從MS黃文雄登載非託管方法:

 [DllImport("gdiplus.dll")] 
     private static extern uint GdipEmfToWmfBits (IntPtr _hEmf, uint _bufferSize, 
      byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags); 
     [DllImport("gdi32.dll")] 
     private static extern IntPtr SetMetaFileBitsEx (uint _bufferSize, 
      byte[] _buffer); 
     [DllImport("gdi32.dll")] 
     private static extern IntPtr CopyMetaFile (IntPtr hWmf, 
      string filename); 
     [DllImport("gdi32.dll")] 
     private static extern bool DeleteMetaFile (IntPtr hWmf); 
     [DllImport("gdi32.dll")] 
     private static extern bool DeleteEnhMetaFile (IntPtr hEmf); 
     private void button4_Click(object sender, System.EventArgs e) 
     { 
      Graphics g= this.CreateGraphics(); 
      IntPtr hDC = g.GetHdc(); 
      Metafile mf = new Metafile(hDC,EmfType.EmfOnly); 
      g.ReleaseHdc(hDC); 
      g.Dispose(); 
      g=Graphics.FromImage(mf); 
      //Pen p = new Pen(Color.White,5); 
      g.DrawArc(Pens.Black,0,0,200,200,0,360); 
      //g.DrawImage(Bitmap.FromFile(@"c:\temp\test.bmp"),0,0); 
      g.Dispose(); 
      IntPtr _hEmf= mf.GetHenhmetafile(); 
      uint _bufferSize = GdipEmfToWmfBits(_hEmf, 0, null, MM_ANISOTROPIC, 
       EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); 
      byte[] _buffer = new byte[_bufferSize]; 
      GdipEmfToWmfBits(_hEmf, _bufferSize, _buffer, MM_ANISOTROPIC, 
        EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); 
      IntPtr hmf = SetMetaFileBitsEx(_bufferSize, _buffer); 
      CopyMetaFile(hmf, "C:\\ConvertedMetafile.wmf"); 
      DeleteMetaFile(hmf); 
      DeleteEnhMetaFile(_hEmf); 
     } 

希望這會讓你那裏:)

+0

非常感謝您對這些鏈接,遺憾的是它並沒有我的情況下工作了... – jdehaan 2011-03-11 12:33:41

+0

好像WMF是「無論如何,在它的出路上。也許這是你爲什麼必須切換到另一種格式的理由? :p – 2011-03-11 13:02:21

+0

是的,我真的不喜歡那些廢話的東西,相信我......我只需要用數據餵養一個老式的工具,它對於支持的格式非常不情願。 – jdehaan 2011-03-11 17:28:38

4

下面是完整的答案這個問題包括我的修改。文森特的答案完全正確。只有一些定義和一個枚舉失蹤。這就是爲什麼我在這裏發佈「乾淨」的工作代碼,希望對別人有用。

 [Flags] 
     private enum EmfToWmfBitsFlags { 
      EmfToWmfBitsFlagsDefault = 0x00000000, 
      EmfToWmfBitsFlagsEmbedEmf = 0x00000001, 
      EmfToWmfBitsFlagsIncludePlaceable = 0x00000002, 
      EmfToWmfBitsFlagsNoXORClip = 0x00000004 
     } 

     private static int MM_ISOTROPIC = 7; 
     private static int MM_ANISOTROPIC = 8; 

     [DllImport ("gdiplus.dll")] 
     private static extern uint GdipEmfToWmfBits (IntPtr _hEmf, uint _bufferSize, 
      byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags); 
     [DllImport ("gdi32.dll")] 
     private static extern IntPtr SetMetaFileBitsEx (uint _bufferSize, 
      byte[] _buffer); 
     [DllImport ("gdi32.dll")] 
     private static extern IntPtr CopyMetaFile (IntPtr hWmf, 
      string filename); 
     [DllImport ("gdi32.dll")] 
     private static extern bool DeleteMetaFile (IntPtr hWmf); 
     [DllImport ("gdi32.dll")] 
     private static extern bool DeleteEnhMetaFile (IntPtr hEmf); 

     private static MemoryStream MakeMetafileStream (Bitmap image) 
     { 
      Metafile metafile = null; 
      using (Graphics g = Graphics.FromImage (image)) { 
       IntPtr hDC = g.GetHdc(); 
       metafile = new Metafile (hDC, EmfType.EmfOnly); 
       g.ReleaseHdc (hDC); 
      } 

      using (Graphics g = Graphics.FromImage (metafile)) { 
       g.DrawImage (image, 0, 0); 
      } 
      IntPtr _hEmf = metafile.GetHenhmetafile(); 
      uint _bufferSize = GdipEmfToWmfBits (_hEmf, 0, null, MM_ANISOTROPIC, 
       EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); 
      byte[] _buffer = new byte[_bufferSize]; 
      GdipEmfToWmfBits (_hEmf, _bufferSize, _buffer, MM_ANISOTROPIC, 
        EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); 
      IntPtr hmf = SetMetaFileBitsEx (_bufferSize, _buffer); 
      string tempfile = Path.GetTempFileName(); 
      CopyMetaFile (hmf, tempfile); 
      DeleteMetaFile (hmf); 
      DeleteEnhMetaFile (_hEmf); 

      var stream = new MemoryStream(); 
      byte[] data = File.ReadAllBytes (tempfile); 
      //File.Delete (tempfile); 
      int count = data.Length; 
      stream.Write (data, 0, count); 
      return stream; 
     } 
+0

感謝您發佈這個!我覺得我的「答案」更基於一些受過教育的Google搜索提供的一系列提示:p – 2013-05-16 11:36:53

+0

男人,我現在愛你......我一直在嘗試用WPF創建兼容wordpad的rtf近一週,並在「從圖像創建一個wmeta文件」的部分殘缺......謝謝 – David 2013-06-24 15:26:50

2

什麼jdehaan發佈了改進版(榮譽順便說一句他和Vincent)

[Flags] 
    private enum EmfToWmfBitsFlags 
    { 
     EmfToWmfBitsFlagsDefault = 0x00000000, 
     EmfToWmfBitsFlagsEmbedEmf = 0x00000001, 
     EmfToWmfBitsFlagsIncludePlaceable = 0x00000002, 
     EmfToWmfBitsFlagsNoXORClip = 0x00000004 
    } 

    private static int MM_ISOTROPIC = 7; 
    private static int MM_ANISOTROPIC = 8; 

    [DllImport("gdiplus.dll")] 
    private static extern uint GdipEmfToWmfBits(IntPtr _hEmf, uint _bufferSize, 
     byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags); 
    [DllImport("gdi32.dll")] 
    private static extern IntPtr SetMetaFileBitsEx(uint _bufferSize, 
     byte[] _buffer); 
    [DllImport("gdi32.dll")] 
    private static extern IntPtr CopyMetaFile(IntPtr hWmf, 
     string filename); 
    [DllImport("gdi32.dll")] 
    private static extern bool DeleteMetaFile(IntPtr hWmf); 
    [DllImport("gdi32.dll")] 
    private static extern bool DeleteEnhMetaFile(IntPtr hEmf); 

    public static MemoryStream MakeMetafileStream(System.Drawing.Bitmap image) 
    { 
     Metafile metafile = null; 
     using (Graphics g = Graphics.FromImage(image)) 
     { 
      IntPtr hDC = g.GetHdc(); 
      metafile = new Metafile(hDC, EmfType.EmfOnly); 
      g.ReleaseHdc(hDC); 
     } 

     using (Graphics g = Graphics.FromImage(metafile)) 
     { 
      g.DrawImage(image, 0, 0); 
     } 
     IntPtr _hEmf = metafile.GetHenhmetafile(); 
     uint _bufferSize = GdipEmfToWmfBits(_hEmf, 0, null, MM_ANISOTROPIC, 
      EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); 
     byte[] _buffer = new byte[_bufferSize]; 
     GdipEmfToWmfBits(_hEmf, _bufferSize, _buffer, MM_ANISOTROPIC, 
       EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); 
     DeleteEnhMetaFile(_hEmf); 

     var stream = new MemoryStream(); 
     stream.Write(_buffer, 0, (int)_bufferSize); 
     stream.Seek(0, 0); 

     return stream; 
    } 

這一個不留臨時文件的背後,也避免了複製_bufferSize到一個臨時文件只能再複製它到另一個緩衝區。 再次感謝你們。

0

這裏是爲我工作一個Win32 GDI +的例子(信貸http://www.codeproject.com/Articles/6879/How-to-use-GDI-to-save-image-in-WMF-EXIF-or-EMF-fo

Bitmap *image; 
image = Bitmap::FromFile(L"in.jpg");    // read in the JPG 
HDC hdc = GetDC(hwnd);        // parent window 
Metafile *metafile = new Metafile(L"out.wmf", hdc); 
Graphics *graphics = new Graphics(metafile); 
graphics->DrawImage(image, 0, 0, image->GetWidth(), image->GetHeight()); 
delete graphics; delete metafile; delete image; 
ReleaseDC(hwnd, hdc);