objeto - GDI+/ C#: ¿Cómo guardar una imagen como EMF?
save system drawing image in folder in c# (9)
Si usa Image.Save Method para guardar una imagen en un EMF / WMF, obtendrá una excepción ( http://msdn.microsoft.com/en-us/library/ktx83wah.aspx )
¿Hay alguna otra forma de guardar la imagen en un EMF / WMF? ¿Hay codificadores disponibles?
Un metarchivo es un archivo que registra una secuencia de operaciones GDI. Es escalable porque se captura la secuencia original de operaciones que generó la imagen y, por lo tanto, las coordenadas que se grabaron se pueden escalar.
Creo que, en .NET, debes crear un objeto Metafile
, crear un objeto Graphics.FromImage
usando Graphics.FromImage
y luego realizar tus pasos de dibujo. El archivo se actualiza automáticamente a medida que dibujas sobre él. Puede encontrar una pequeña muestra en la documentación de Graphics.AddMetafileComment .
Si realmente desea almacenar un mapa de bits en un metarchivo, siga estos pasos y luego use Graphics.DrawImage
para pintar el mapa de bits. Sin embargo, cuando se escala, se StretchBlt
con StretchBlt
.
La pregunta era: "¿Hay alguna otra forma de guardar la imagen en un EMF / WMF?" No "qué es un metarchivo" o "cómo crear un metarchivo" o "cómo usar un metarchivo con gráficos".
También busco la respuesta para esta pregunta "cómo guardar EMF / WMF" De hecho, si usa:
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);
En ambos casos, la imagen se guarda como formato png. Y este es el problema que no puedo resolver: /
La respuesta de erikkallen es correcta. Intenté esto desde VB.NET y tuve que usar 2 DllImports diferentes para que funcione:
<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
La primera importación se usa para la primera llamada para obtener el tamaño de fem. La segunda importación para obtener los bits reales. Alternativamente podrías usar:
Dim h As IntPtr = mf.GetHenhmetafile()
CopyEnhMetaFileW(h, FileName)
Esto copia los bits emf directamente en el archivo nombrado.
Estaba buscando una forma de guardar las instrucciones GDI en un objeto Metafile en un archivo EMF. La publicación de Han me ayudó a resolver el problema. Esto fue antes de unirme a SOF. Gracias, Han. Esto es lo que intenté .
[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);
Parece que hay mucha confusión sobre vector vs. mapa de bits. Todo el código en este subproceso genera archivos de mapa de bits (no vectoriales); no conserva las llamadas vectoriales GDI. Para demostrarte esto, descarga la herramienta "EMF Parser" e inspecciona los archivos de salida: http://downloads.zdnet.com/abstract.aspx?docid=749645 .
Este problema ha causado que muchos desarrolladores consideren la angustia. Seguro que estaría bien si Microsoft solucionara esto y respaldara adecuadamente su propio formato EMF.
También debe cerrar el controlador CopyEnhMetaFile
:
IntPtr ptr2 = CopyEnhMetaFile(iptrMetafileHandle, "image.emf");
DeleteEnhMetaFile(ptr2);
// Delete the metafile from memory
DeleteEnhMetaFile(iptrMetafileHandle);
De lo contrario, no puede eliminar el archivo porque todavía lo usa el proceso.
Si recuerdo correctamente, se puede hacer con una combinación de Metafile.GetHenhmetafile (), API GetEnhMetaFileBits () y Stream.Write (), algo así como
[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.
Creo que así es como resolví el problema cuando lo tuve.
Recomendaría evitar tales externalidades y errores no administrados en una aplicación .NET administrada. En cambio, recomendaría algo un poco más parecido a la solución administrada que figura en este hilo:
Convierte una imagen en WMF con .NET?
PD. Estoy respondiendo a este viejo hilo porque esta fue la mejor respuesta que encontré, pero luego terminé desarrollando una solución administrada, que luego me llevó al enlace de arriba. Entonces, para salvar a los demás esa vez, pensé que podría apuntar este a esa.
Image
es una clase abstracta: lo que quiere hacer depende de si está tratando con un Metafile
o un Bitmap
.
Crear una imagen con GDI + y guardarla como un EMF es simple con Metafile
. Por la publicación de Mike:
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();
Esto es lo que desea hacer la mayor parte del tiempo, ya que eso es para lo que es EMF: guardar imágenes vectoriales en forma de comandos de dibujo GDI +.
Puede guardar un Bitmap
de Bitmap
en un archivo EMF utilizando el método anterior y llamando a ig.DrawImage(your_bitmap)
, pero tenga en cuenta que esto no encubierta mágicamente sus datos ráster en una imagen vectorial.