问题
If you use Image.Save Method to save an image to a EMF/WMF, you get an exception (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?
回答1:
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.
回答2:
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")] 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.
I think this is how I solved the problem when I had it.
回答3:
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
.
回答4:
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 :/
回答5:
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.
回答6:
You also need to close the CopyEnhMetaFile
handler:
IntPtr ptr2 = CopyEnhMetaFile(iptrMetafileHandle, "image.emf");
DeleteEnhMetaFile(ptr2);
// Delete the metafile from memory
DeleteEnhMetaFile(iptrMetafileHandle);
Otherwise, you cannot delete the file because it's still used by the process.
回答7:
I would recommend avoiding such extern's and unmanaged cruft in a managed .NET app. Instead, I'd recommend something a bit more like the managed solution given in this thread:
Convert an image into WMF with .NET?
P.S. I am answering this old thread because this was the best answer I had found, but then ended up developing a managed solution, which then lead me to the link above. So, to save others that time, I figured I'd point this one to that one.
回答8:
I was looking for a way to save the GDI instructions in a Metafile object to a EMF file. Han's post helped me solve the problem. This was before I joined SOF. Thank you, Han. Here is what 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:
It appears there is much confusion over vector vs. bitmap. All of the code in this thread generates bitmap (non-vector) files - it does not preserve the vector GDI calls. To prove this to yourself, download the "EMF Parser" tool and inspect the output files: http://downloads.zdnet.com/abstract.aspx?docid=749645.
This issue has caused many developers considering anguish. Sure would be nice if Microsoft would fix this and properly support their own EMF format.
来源:https://stackoverflow.com/questions/152729/gdi-c-how-to-save-an-image-as-emf