If you use Image.Save Method to save an image to a EMF/WMF, you got an exceptoin (http://msdn.microsoft.com/en-us/library/ktx83wah.aspx)
Is there another way to save the image to an EMF/WMF? Are there any encoders available?
Thanks Eric
If you use Image.Save Method to save an image to a EMF/WMF, you got an exceptoin (http://msdn.microsoft.com/en-us/library/ktx83wah.aspx)
Is there another way to save the image to an EMF/WMF? Are there any encoders available?
Thanks Eric
A metafile is a file which records a sequence of GDI operations. It is scalable because the original sequence of operations that generated the picture are captured, and therefore the co-ordinates that were recorded can be scaled.
I think, in .NET, that you should create a Metafile
object, create a Graphics
object using Graphics.FromImage
, then perform your drawing steps. The file is automatically updated as you draw on it. You can find a small sample in the documentation for Graphics.AddMetafileComment.
If you really want to store a bitmap in a metafile, use these steps then use Graphics.DrawImage
to paint the bitmap. However, when it is scaled it will be stretched using StretchBlt
.
The question was: "Is there another way to save the image to an EMF/WMF?" Not "what is metafile" or "how to create metafile" or "how to use metafile with Graphics".
I also look for answer for this question "how to save EMF/WMF" In fact if you use:
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);
In both cases image is saved as format png. And this is the problem which I cannot solve :/
If I remember correctly, it can be done with a combination of the Metafile.GetHenhmetafile(), the API GetEnhMetaFileBits() and Stream.Write(), something like
[DllImport("gdi32")] uint GetEnhMetaFileBits(IntPtr hemf, uint cbBuffer, byte[] lpbBuffer);
IntPtr h = metafile.GetHenhMetafile();
int size = GetEnhMetaFileBits(h, 0, 0);
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.
I think this is how I solved the problem when I had it.
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.
Image
is an abstract class: what you want to do depends on whether you are dealing with a Metafile
or a Bitmap
.
Creating an image with GDI+ and saving it as an EMF is simple with Metafile
. Per Mike's 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();
This is what you want to do most of the time, since that is what EMF is for: saving vector images in the form of GDI+ drawing commands.
You can save a Bitmap
to an EMF file by using the above method and calling ig.DrawImage(your_bitmap)
, but be aware that this does not magically covert your raster data into a vector image.
How would you parse a WMF or EMF file? By parse I mean break it down into lines, arcs, etc. I tried using a EnumerateMetafileProc but there are no types for the EmfPlusRecordType enum.