A few days ago when I was building the MS-OLEDS file for AutoCAD, I needed to create a Metafile as part of it. However, I encountered some small problems when using the built-in API.
The Problem with Built-in API
In System.Drawing.Imaging has a Metafile Class that allows us do a sequence of graphics operations on it.Here is my code and the test file in the HEX editor.
public static void GenerateMetafile(Image image, string filePath)
{
Metafile metafile = null;
using (Graphics graphics = Graphics.FromImage(image))
{
var hdc = graphics.GetHdc();
metafile = new Metafile(filePath, hdc);
graphics.ReleaseHdc(hdc);
}
using (Graphics graphics = Graphics.FromImage(metafile))
{
graphics.DrawImage(image, 0, 0);
}
}
Everything looks fine,but when I save it into MS-OLEDS and open it with AutoCAD,I got nothing.In the end I found out that the built-in API does not have a wmf encoder.
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.
The Solution with Win32 API
Finally, I found a solution using Win32 API with the correct encoder.Here is the solution code,You can use the GenerateMetafile method to get the matefile stream.
public class MetafileUtils
{
[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 bool DeleteEnhMetaFile(IntPtr hEmf);
public static MemoryStream GenerateMetafile(Image image)
{
Metafile metafile = null;
using (Graphics graphics = Graphics.FromImage(image))
{
var hdc = graphics.GetHdc();
metafile = new Metafile(hdc, EmfType.EmfOnly);
graphics.ReleaseHdc(hdc);
}
using (Graphics graphics = Graphics.FromImage(metafile))
{
graphics.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;
}
}