2011-03-11 106 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);