GDI + / C#:如何将图像保存为EMF?

如果使用Image.Save方法将图像保存到EMF / WMF,则会出现exception( http://msdn.microsoft.com/en-us/library/ktx83wah.aspx )

还有另一种方法可以将图像保存到EMF / WMF吗? 有没有可用的编码器?

Image是一个抽象类:您想要做什么取决于您是在处理Metafile还是Bitmap

使用Metafile使用GDI +创建图像并将其另存为EMF非常简单。 每个迈克的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 +绘图命令的forms保存矢量图像。

您可以使用上述方法并调用ig.DrawImage(your_bitmap)Bitmap保存到EMF文件,但请注意,这不会将您的栅格数据神奇地转换为矢量图像。

如果我没记错的话,可以使用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. 

我认为这就是我解决问题的方法。

元文件是记录一系列GDI操作的文件。 它是可缩放的,因为捕获了生成图像的原始操作序列,因此可以缩放记录的坐标。

我认为,在.NET中,您应该创建一个Metafile对象,使用Graphics.FromImage创建一个Graphics对象,然后执行绘制步骤。 在您绘制文件时,文件会自动更新。 您可以在Graphics.AddMetafileComment的文档中找到一个小样本。

如果您确实想在元文件中存储位图,请使用这些步骤,然后使用Graphics.DrawImage绘制位图。 但是,当它被缩放时,它将使用StretchBlt进行拉伸。

问题是:“还有另一种方法可以将图像保存到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。 这是我无法解决的问题:/

erikkallen的回答是正确的。 我从VB.NET尝试过这个,并且必须使用2个不同的DllImports才能使它工作:

  _ Public Shared Function GetEnhMetaFileBits( ByVal hEMF As System.IntPtr, ByVal nSize As UInteger, ByVal lpData As IntPtr) As UInteger End Function  _ Public Shared Function GetEnhMetaFileBits( ByVal hEMF As System.IntPtr, ByVal nSize As UInteger, ByVal lpData() As Byte) As UInteger End Function 

第一次导入用于第一次调用以获得emf大小。 获取实际位的第二个导入。 或者你可以使用:

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

这会将emf位直接复制到指定的文件。

您还需要关闭CopyEnhMetaFile处理程序:

 IntPtr ptr2 = CopyEnhMetaFile(iptrMetafileHandle, "image.emf"); DeleteEnhMetaFile(ptr2); // Delete the metafile from memory DeleteEnhMetaFile(iptrMetafileHandle); 

否则,您无法删除该文件,因为该进程仍在使用该文件。

我建议在托管的.NET应用程序中避免使用这种extern和unmanaged cruft。 相反,我建议更像这个线程中给出的托管解决方案:

用.NET将图像转换为WMF?

PS我正在回答这个旧线程,因为这是我找到的最佳答案,但后来最终开发了一个托管解决方案,然后引导我进入上面的链接。 所以,为了节省其他时间,我想我会把这个指向那一个。

我一直在寻找一种方法将Metafile对象中的GDI指令保存到EMF文件中。 韩的post帮我解决了这个问题。 这是在我加入SOF之前。 谢谢韩。 这是我尝试过的 。

     [的DllImport( “GDI32.DLL”)]
     static extern IntPtr CopyEnhMetaFile(//将EMF复制到文件
         IntPtr hemfSrc,//处理EMF
         String lpszFile //文件
     );

     [的DllImport( “GDI32.DLL”)]
     static extern int DeleteEnhMetaFile(//删除EMF
         IntPtr hemf //处理EMF
     );

    //创建图元文件的代码 
    // Metafile元文件= ...

    //获取元文件的句柄
    IntPtr iptrMetafileHandle = metafile.GetHenhmetafile();

    //将图元文件导出到图像文件
    CopyEnhMetaFile(
          iptrMetafileHandle, 
           “image.emf”);

    //从内存中删除元文件
    DeleteEnhMetaFile(iptrMetafileHandle);

看起来有很多关于矢量与位图的混淆。 此线程中的所有代码都生成位图(非向量)文件 – 它不保留向量GDI调用。 要自己certificate这一点,请下载“EMF Parser”工具并检查输出文件: http : //downloads.z​​dnet.com/abstract.aspx?docid = 749645 。

这个问题导致许多开发人员考虑痛苦。 如果微软能够解决这个问题并正确支持他们自己的EMF格式,那肯定会很好。