代码之家  ›  专栏  ›  技术社区  ›  EricSch

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

  •  18
  • EricSch  · 技术社区  · 17 年前

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

    有没有其他方法将图像保存到EMF/WMF? 有编码器吗?

    9 回复  |  直到 9 年前
        1
  •  21
  •   Community Mohan Dere    9 年前

    Image 是一个抽象类:你想做什么取决于你是否在处理 Metafile 或者 Bitmap

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

    你可以保存一个 位图 使用上述方法并调用 ig.DrawImage(your_bitmap) ,但请注意,这不会神奇地将光栅数据转换为矢量图像。

        2
  •  12
  •   Dan Monego    13 年前

    [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.
    

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

        3
  •  3
  •   Mike Dimmick    17 年前

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

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

    Graphics.DrawImage 绘制位图。但是,当它被缩放时,它将使用 StretchBlt

        4
  •  3
  •   Greg Greg    17 年前

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

        5
  •  2
  •   Han    17 年前

    埃里克伦的回答是正确的。我在VB.NET中尝试过,并且必须使用两个不同的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
    

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

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

        6
  •  2
  •   Raul Rene    14 年前

    你还需要关闭 CopyEnhMetaFile 经办人:

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

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

        7
  •  1
  •   Community Mohan Dere    9 年前

    相反,我推荐一些更类似于此线程中给出的托管解决方案的内容:

    Convert an image into WMF with .NET?

    P、 我之所以回答这个老问题,是因为这是我找到的最好的答案,但最终开发出了一个托管解决方案,然后将我引向上面的链接。所以,为了节省其他人的时间,我想我应该把这个指向那个。

        8
  •  0
  •   BZ1    15 年前

    我正在寻找一种将元文件对象中的GDI指令保存到EMF文件的方法。韩寒的帖子帮我解决了这个问题。这是在我加入特种部队之前。谢谢你,韩。这是什么 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);
    
    
        9
  •  0
  •   Roger    15 年前

    矢量和位图之间似乎有很多混淆。此线程中的所有代码都会生成位图(非矢量)文件—它不会保留矢量GDI调用。要证明这一点,请下载“EMF解析器”工具并检查输出文件: http://downloads.zdnet.com/abstract.aspx?docid=749645 .