【问题标题】:Convert an image into WMF with .NET?使用 .NET 将图像转换为 WMF?
【发布时间】:2011-07-13 08:21:39
【问题描述】:

有很多将 wmf 转换为位图的示例,例如: Reliable .wmf/wmf to Pixel based image conversion

但我需要反向操作。我不寻找矢量化器。我只想在 wmf 文件中嵌入图片,而不必担心 wmf 格式的位和字节。我需要一个 .NET 的解决方案,最好在 C# 中。

我首先认为这可以完成这项工作:

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

但这会在运行时抱怨编码器为空。我在哪里/如何构建这样的编码器?我不需要一个复杂的,只需要一个将图像包装成 wmf 的。 WMF 中支持的格式是否有一些要求?我想支持 png 和 bmp 但也支持 gif 吗?

【问题讨论】:

    标签: .net image bitmap encode wmf


    【解决方案1】:

    来自here

    当你使用 Save 方法保存一个 图形图像作为 Windows 元文件 格式 (WMF) 或增强的元文件 格式化 (EMF) 文件,生成的文件 保存为便携式网络 图形 (PNG) 文件。这 出现这种行为是因为 GDI+ .NET Framework 的组件确实 没有可以使用的编码器 将文件保存为 .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 的 Peter Huang 发布了这种非托管方法:

            [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);
            }
    

    希望这能让你到达那里:)

    【讨论】:

    • 非常感谢您提供这些链接,不幸的是它在我的情况下没有成功...
    • 无论如何,WMF 似乎“即将结束”。也许这是你为什么必须切换到另一种格式的论据? :p
    • 是的,我不是很喜欢那些垃圾东西,相信我...我只需要用数据提供一个旧的既定工具,它对支持的格式非常不情愿。
    • 非托管方法通过一些更改得到了解决,感谢您的提示!
    • 对我来说,“旧工具”是 .Net 中的 RichTextBox。恼人的是它不支持 jpeg 或 png 图像。基本上使用 .Net,您无法使用 .Net 内置的 RTF 控件创建带有可查看图像的 RTF 文件。
    【解决方案2】:

    这是问题的完整答案,包括我的修改。文森特的回答是完全正确的。只有一些定义和一个枚举丢失。这就是为什么我在这里发布“干净”的工作代码,希望它对其他人有用。

            [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;
            }
    

    【讨论】:

    • 感谢您发布此信息!我觉得我的“答案”更多的是基于一些受过教育的谷歌搜索的一系列提示:p
    • 伙计,我现在爱你...我一直在尝试使用 WPF 创建与写字板兼容的 rtf 近一个星期,并且在“从图像创建 wmetafile”上陷入困境部分...谢谢
    【解决方案3】:

    jdehaan 发布的内容的改进版本(对他和文森特表示敬意)

        [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 复制到临时文件,然后将其复制到另一个缓冲区。 再次感谢大家。

    【讨论】:

      【解决方案4】:

      这是一个对我有用的 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);
      

      【讨论】:

        猜你喜欢
        • 2018-10-17
        • 2013-10-29
        • 2010-10-21
        • 2020-11-24
        • 2013-06-26
        • 1970-01-01
        • 1970-01-01
        • 2011-01-29
        • 2012-12-26
        相关资源
        最近更新 更多