Convirtiendo BitmapImage a Bitmap y viceversa

Tengo BitmapImage en C #. Necesito hacer operaciones en imagen. Por ejemplo, grayscaling, agregar texto en la imagen, etc.

He encontrado la función en stackoverflow para grayscaling que acepta Bitmap y devuelve Bitmap.

Entonces necesito convertir BitmapImage a Bitmap, hacer operación y convertir de nuevo.

¿Cómo puedo hacer esto? ¿Es esta la mejor manera?

No es necesario usar bibliotecas extranjeras.

Convertir una imagen de bitmap en bitmap:

private Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage) { // BitmapImage bitmapImage = new BitmapImage(new Uri("../Images/test.png", UriKind.Relative)); using(MemoryStream outStream = new MemoryStream()) { BitmapEncoder enc = new BmpBitmapEncoder(); enc.Frames.Add(BitmapFrame.Create(bitmapImage)); enc.Save(outStream); System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream); return new Bitmap(bitmap); } } 

Para convertir el bitmap a una imagen de bitmap:

 [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); private BitmapImage Bitmap2BitmapImage(Bitmap bitmap) { IntPtr hBitmap = bitmap.GetHbitmap(); BitmapImage retval; try { retval = (BitmapImage)Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } finally { DeleteObject(hBitmap); } return retval; } 

Aquí hay un método de extensión para convertir un bitmap a BitmapImage.

  public static BitmapImage ToBitmapImage(this Bitmap bitmap) { using (var memory = new MemoryStream()) { bitmap.Save(memory, ImageFormat.Png); memory.Position = 0; var bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.StreamSource = memory; bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.EndInit(); bitmapImage.Freeze(); return bitmapImage; } } 

Si solo necesitas pasar de BitmapImage a Bitmap, es bastante fácil,

 private Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage) { return new Bitmap(bitmapImage.StreamSource); } 

usando System.Windows.Interop; …

  private BitmapImage Bitmap2BitmapImage(Bitmap bitmap) { BitmapSource i = Imaging.CreateBitmapSourceFromHBitmap( bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); return (BitmapImage)i; } 

He intentado usar lo anterior en mi código y creo que hay un problema con la función Bitmap2BitmapImage (y posiblemente también con la otra).

 using (MemoryStream ms = new MemoryStream()) 

¿La línea anterior da como resultado la eliminación de la stream? Lo que significa que el BitmapImage devuelto pierde su contenido.

Como soy un novato de WPF, no estoy seguro de que esta sea la explicación técnica correcta, pero el código no funcionó en mi aplicación hasta que eliminé la directiva de uso.

Aquí la versión asincrónica.

 public static Task ToBitmapSourceAsync(this Bitmap bitmap) { return Task.Run(() => { using (System.IO.MemoryStream memory = new System.IO.MemoryStream()) { bitmap.Save(memory, ImageFormat.Png); memory.Position = 0; BitmapImage bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.StreamSource = memory; bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.EndInit(); bitmapImage.Freeze(); return bitmapImage as BitmapSource; } }); } 

Esto convierte de System.Drawing.Bitmap a BitmapImage:

 MemoryStream ms = new MemoryStream(); YOURBITMAP.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); BitmapImage image = new BitmapImage(); image.BeginInit(); ms.Seek(0, SeekOrigin.Begin); image.StreamSource = ms; image.EndInit(); 

Gracias Guillermo Hernández, creé una variación de tu código que funciona. Agregué los espacios de nombres en este código para referencia.

 System.Reflection.Assembly theAsm = Assembly.LoadFrom("My.dll"); // Get a stream to the embedded resource System.IO.Stream stream = theAsm.GetManifestResourceStream(@"picture.png"); // Here is the most important part: System.Windows.Media.Imaging.BitmapImage bmi = new BitmapImage(); bmi.BeginInit(); bmi.StreamSource = stream; bmi.EndInit();