GDI + / C #: ¿Cómo guardar una imagen como EMF?

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?

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.

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.

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 bitmap en un metarchivo, siga estos pasos y luego use Graphics.DrawImage para pintar el bitmap. 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:

  _ Public Shared Function GetEnhMetaFileBits( ByVal hEMF As System.IntPtr, ByVal nSize As UInteger, ByVal lpData As IntPtr) As UInteger End Function  _ Public Shared Function GetEnhMetaFileBits( 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.

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.

Recomendaría evitar tales externalidades y errores no administrados en una aplicación .NET administrada. En su lugar, recomendaría algo un poco más parecido a la solución administrada proporcionada 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.

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 (// Copia de EMF al archivo
         IntPtr hemfSrc, // Manejar a EMF
         Cadena lpszFile // Archivo
     );

     [DllImport ("gdi32.dll")]
     static extern int DeleteEnhMetaFile (// Eliminar EMF
         IntPtr hemf // Manejar a CEM
     );

    // Código que crea el metarchivo 
    // Metafile metarchivo = ...

    // Obtener un control para el metarchivo
    IntPtr iptrMetafileHandle = metarchivo.GetHenhmetafile ();

    // Exportar metarchivo a un archivo de imagen
    CopyEnhMetaFile (
          iptrMetafileHandle, 
           "image.emf");

    // Eliminar el metarchivo de la memoria
    DeleteEnhMetaFile (iptrMetafileHandle);

Parece que hay mucha confusión sobre vector vs. bitmap. Todo el código en este subproceso genera archivos de bitmap (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.