Search code examples
.netimagebitmapencodewmf

Convert an image into WMF with .NET?


There are plenty of examples of converting a wmf into a bitmap like: Reliable .wmf/wmf to Pixel based image conversion

But I need the reverse operation. I do not look for a vectorizer. I just want to embed a picture inside a wmf file without having to bother about the bits and bytes of the wmf format. I need a solution for .NET preferably in C#.

I first thought this would do the job:

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

But this complains at runtime that the encoder is null. Where/How can I build such an encoder? I do not need a complicated one, just one that wraps an image into a wmf. Are there some requirements on the supported formats in WMF? I suppose png and bmp are supported but is gif also supported?


Solution

  • From here:

    When you use the Save method to save a graphic image as a Windows Metafile Format (WMF) or Enhanced Metafile Format (EMF) file, the resulting file is saved as a Portable Network Graphics (PNG) file instead. This behavior occurs because the GDI+ component of the .NET Framework does not have an encoder that you can use to save files as .wmf or .emf files.

    But I guess you already got that far :)

    Here someone is putting a bitmap in a FileStream.

    metafileStream = MakeMetafileStream(gdiBitmap);
    

    with MakeMetafileStream() being:

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

    Interesting stuff. But as to the encoder thing...

    Here Peter Huang from MS posted this unmanaged approach:

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

    Hope this'll get you there :)