img - Convierte una imagen en WMF con.NET?
system drawing image vb net (4)
Desde aquí :
Cuando utiliza el método Guardar para guardar una imagen gráfica como un formato de metarchivo de Windows (WMF) o un archivo de formato de metarchivo mejorado (EMF), el archivo resultante se guarda como un archivo de gráficos de red portátiles (PNG). Este comportamiento se produce porque el componente GDI + de .NET Framework no tiene un codificador que puede usar para guardar archivos como archivos .wmf o .emf.
Pero supongo que ya has llegado tan lejos :)
Aquí alguien está poniendo un mapa de bits en un FileStream.
metafileStream = MakeMetafileStream(gdiBitmap);
con MakeMetafileStream () siendo:
private static MemoryStream MakeMetafileStream(Bitmap image)
{
Graphics graphics = null;
Metafile metafile= null;
var stream = new MemoryStream();
try
{
using (graphics = Graphics.FromImage(image))
{
var hdc = graphics.GetHdc();
metafile= new Metafile(stream, hdc);
graphics.ReleaseHdc(hdc);
}
using (graphics = Graphics.FromImage(metafile))
{ graphics.DrawImage(image, 0, 0); }
}
finally
{
if (graphics != null)
{ graphics.Dispose(); }
if (metafile!= null)
{ metafile.Dispose(); }
}
return stream;
}
Cosas interesantes. Pero en cuanto a la cosa del codificador ...
Aquí Peter Huang de MS publicó este enfoque no gestionado:
[DllImport("gdiplus.dll")]
private static extern uint GdipEmfToWmfBits (IntPtr _hEmf, uint _bufferSize,
byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags);
[DllImport("gdi32.dll")]
private static extern IntPtr SetMetaFileBitsEx (uint _bufferSize,
byte[] _buffer);
[DllImport("gdi32.dll")]
private static extern IntPtr CopyMetaFile (IntPtr hWmf,
string filename);
[DllImport("gdi32.dll")]
private static extern bool DeleteMetaFile (IntPtr hWmf);
[DllImport("gdi32.dll")]
private static extern bool DeleteEnhMetaFile (IntPtr hEmf);
private void button4_Click(object sender, System.EventArgs e)
{
Graphics g= this.CreateGraphics();
IntPtr hDC = g.GetHdc();
Metafile mf = new Metafile(hDC,EmfType.EmfOnly);
g.ReleaseHdc(hDC);
g.Dispose();
g=Graphics.FromImage(mf);
//Pen p = new Pen(Color.White,5);
g.DrawArc(Pens.Black,0,0,200,200,0,360);
//g.DrawImage(Bitmap.FromFile(@"c:/temp/test.bmp"),0,0);
g.Dispose();
IntPtr _hEmf= mf.GetHenhmetafile();
uint _bufferSize = GdipEmfToWmfBits(_hEmf, 0, null, MM_ANISOTROPIC,
EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
byte[] _buffer = new byte[_bufferSize];
GdipEmfToWmfBits(_hEmf, _bufferSize, _buffer, MM_ANISOTROPIC,
EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault);
IntPtr hmf = SetMetaFileBitsEx(_bufferSize, _buffer);
CopyMetaFile(hmf, "C://ConvertedMetafile.wmf");
DeleteMetaFile(hmf);
DeleteEnhMetaFile(_hEmf);
}
Espero que esto te lleve allí :)
Hay muchos ejemplos de cómo convertir un archivo wmf en un mapa de bits, por ejemplo: conversión confiable de imágenes .wmf / wmf a píxel.
Pero necesito la operación inversa. No busco un vectorizador. Solo quiero insertar una imagen dentro de un archivo wmf sin tener que preocuparme por los bits y bytes del formato wmf. Necesito una solución para .NET preferiblemente en C #.
Primero pensé que esto haría el trabajo:
using (Image img = Image.FromFile (path)) {
img.Save (myStream, System.Drawing.Imaging.ImageFormat.Wmf);
}
Pero esto se queja en tiempo de ejecución de que el codificador es nulo. ¿Dónde / Cómo puedo construir tal codificador? No necesito uno complicado, solo uno que envuelve una imagen en un wmf. ¿Hay algunos requisitos en los formatos compatibles en WMF? Supongo que png y bmp son compatibles pero también es compatible con gif?
Aquí está la respuesta completa a la pregunta, incluidas mis modificaciones. La respuesta de Vincent es completamente correcta. Solo faltaban algunas definiciones y una enumeración. Es por eso que publico aquí el código de trabajo "limpio" con la esperanza de que pueda ser útil para otra persona.
[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 IntPtr SetMetaFileBitsEx (uint _bufferSize,
byte[] _buffer);
[DllImport ("gdi32.dll")]
private static extern IntPtr CopyMetaFile (IntPtr hWmf,
string filename);
[DllImport ("gdi32.dll")]
private static extern bool DeleteMetaFile (IntPtr hWmf);
[DllImport ("gdi32.dll")]
private static extern bool DeleteEnhMetaFile (IntPtr hEmf);
private static MemoryStream MakeMetafileStream (Bitmap image)
{
Metafile metafile = null;
using (Graphics g = Graphics.FromImage (image)) {
IntPtr hDC = g.GetHdc ();
metafile = new Metafile (hDC, EmfType.EmfOnly);
g.ReleaseHdc (hDC);
}
using (Graphics g = Graphics.FromImage (metafile)) {
g.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);
IntPtr hmf = SetMetaFileBitsEx (_bufferSize, _buffer);
string tempfile = Path.GetTempFileName ();
CopyMetaFile (hmf, tempfile);
DeleteMetaFile (hmf);
DeleteEnhMetaFile (_hEmf);
var stream = new MemoryStream ();
byte[] data = File.ReadAllBytes (tempfile);
//File.Delete (tempfile);
int count = data.Length;
stream.Write (data, 0, count);
return stream;
}
Una versión mejorada de lo que jdehaan publicó (felicitaciones por él y Vincent)
[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 IntPtr SetMetaFileBitsEx(uint _bufferSize,
byte[] _buffer);
[DllImport("gdi32.dll")]
private static extern IntPtr CopyMetaFile(IntPtr hWmf,
string filename);
[DllImport("gdi32.dll")]
private static extern bool DeleteMetaFile(IntPtr hWmf);
[DllImport("gdi32.dll")]
private static extern bool DeleteEnhMetaFile(IntPtr hEmf);
public static MemoryStream MakeMetafileStream(System.Drawing.Bitmap image)
{
Metafile metafile = null;
using (Graphics g = Graphics.FromImage(image))
{
IntPtr hDC = g.GetHdc();
metafile = new Metafile(hDC, EmfType.EmfOnly);
g.ReleaseHdc(hDC);
}
using (Graphics g = Graphics.FromImage(metafile))
{
g.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;
}
Este no deja archivos temporales atrás y también evita copiar _bufferSize a un archivo temporal solo para luego copiarlo a otro buffer. Gracias de nuevo chicos.
Aquí hay un ejemplo de Win32 GDI + que funcionó para mí (crédito a http://www.codeproject.com/Articles/6879/How-to-use-GDI-to-save-image-in-WMF-EXIF-or-EMF- fo )
Bitmap *image;
image = Bitmap::FromFile(L"in.jpg"); // read in the JPG
HDC hdc = GetDC(hwnd); // parent window
Metafile *metafile = new Metafile(L"out.wmf", hdc);
Graphics *graphics = new Graphics(metafile);
graphics->DrawImage(image, 0, 0, image->GetWidth(), image->GetHeight());
delete graphics; delete metafile; delete image;
ReleaseDC(hwnd, hdc);