18

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

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

4

9 回答 9

22

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

使用 GDI+ 创建图像并将其保存为 EMF 很简单,使用Metafile. 根据迈克的帖子

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+ 绘图命令的形式保存矢量图像。

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

于 2009-06-10T21:51:52.327 回答
12

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

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

于 2009-04-09T09:17:30.543 回答
3

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

于 2009-03-27T04:47:31.103 回答
3

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

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

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

于 2008-09-30T12:31:40.577 回答
2

The answer by erikkallen is correct. I tried this from VB.NET, and had to use 2 different DllImports to get it to work:

<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

The first import is used for the first call to get the emf size. The second import to get the actual bits. Alternatively you could use:

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

This copies the emf bits directly to the named file.

于 2009-05-21T21:14:36.353 回答
2

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

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

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

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

于 2012-05-09T03:31:56.123 回答
1

我建议在托管的 .NET 应用程序中避免使用此类外部和非托管垃圾。相反,我会推荐一些更像这个线程中给出的托管解决方案的东西:

使用 .NET 将图像转换为 WMF?

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

于 2012-08-17T15:17:25.507 回答
1

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

    [DllImport("gdi32.dll")]
    static extern IntPtr CopyEnhMetaFile( // 复制 EMF 到文件
        IntPtr hemfSrc, // EMF 句柄
        字符串 lpszFile // 文件
    );

    [DllImport("gdi32.dll")]
    static extern int DeleteEnhMetaFile( // 删除 EMF
        IntPtr hemf // EMF 句柄
    );

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

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

   // 将元文件导出为图像文件
   CopyEnhMetaFile(
         iptr元文件句柄,
          “图像.emf”);

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

于 2011-03-03T11:31:32.630 回答
0

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

这个问题引起了很多开发者考虑的苦恼。如果微软能解决这个问题并正确支持他们自己的 EMF 格式,那当然会很好。

于 2011-04-01T14:00:14.397 回答