2010-02-17 14 views
35

Por lo que yo puedo decir la única manera de convertir de BitmapSource de mapa de bits es a través de código no seguro ... ¿Te gusta esta (de Lesters WPF blog):¿Existe una buena manera de convertir BitmapSource a Bitmap?

myBitmapSource.CopyPixels(bits, stride, 0); 

unsafe 
{ 
    fixed (byte* pBits = bits) 
    { 
     IntPtr ptr = new IntPtr(pBits); 

     System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(
     width, 
     height, 
     stride, 
     System.Drawing.Imaging.PixelFormat.Format32bppPArgb,ptr); 

     return bitmap; 
    } 
} 

hacer lo contrario:

System.Windows.Media.Imaging.BitmapSource bitmapSource = 
    System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
    bitmap.GetHbitmap(), 
    IntPtr.Zero, 
    Int32Rect.Empty, 
    System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); 

¿Hay alguna manera más fácil en el marco? ¿Y cuál es la razón por la que no está ahí (si no es así)? Creo que es bastante utilizable.

La razón por la que lo necesito es porque uso AForge para realizar ciertas operaciones de imagen en una aplicación WPF. WPF quiere mostrar BitmapSource/ImageSource pero AForge funciona en Bitmaps.

+10

Para hacer lo contrario, * realmente * ** debe ** eliminar el identificador de mapa de bits que obtiene con 'GetHbitmap'. Este error está en todo internet. No se puede arreglar El mundo está goteando lentamente los identificadores de GDI; pronto estaremos nadando en ellos! –

+0

Thx, para señalar :) – JohannesH

+2

romkyns se refiere a esto: http://stackoverflow.com/questions/1546091/wpf-createbitmapsourcefromhbitmap-memory-leak –

Respuesta

54

Es posible hacerlo sin utilizar código no seguro mediante el uso de Bitmap.LockBits y copiar los píxeles de la BitmapSource directamente a la Bitmap

Bitmap GetBitmap(BitmapSource source) { 
    Bitmap bmp = new Bitmap(
    source.PixelWidth, 
    source.PixelHeight, 
    PixelFormat.Format32bppPArgb); 
    BitmapData data = bmp.LockBits(
    new Rectangle(Point.Empty, bmp.Size), 
    ImageLockMode.WriteOnly, 
    PixelFormat.Format32bppPArgb); 
    source.CopyPixels(
    Int32Rect.Empty, 
    data.Scan0, 
    data.Height * data.Stride, 
    data.Stride); 
    bmp.UnlockBits(data); 
    return bmp; 
} 
+4

Eso funcionaría solo si el formato de píxeles se conoce de antemano, es más o menos la forma en que fui y la función adicional para asignar entre formatos de píxeles. – JohannesH

+0

¿Funciona esto con WPF? El mapa de bits parece provenir de System.Drawing y se usa en WinForms. Sin embargo, BitmapSource se usa en WPF. – Jonas

+0

El código anterior se utiliza para convertir un WPF BitmapSource en un Windows Forms Bitmap, el código debería "funcionar" en WPF, siempre que se mencionen los ensamblajes correctos, sin embargo, no será muy útil ya que si ya tiene un BitmapSource puede usar directamente en WPF. –

2

¿Esto es lo que estás buscando?

Bitmap bmp = System.Drawing.Image.FromHbitmap(pBits); 
+2

No creo que esto sea correcto: está pasando un puntero a una matriz de bytes donde, en cambio, esperaba un identificador de mapa de bits de Win32. - Gracias por señalar que esta función existe, eso está bien. – BrainSlugs83

27

Usted sólo puede usar estos dos métodos:

public static BitmapSource ConvertBitmap(Bitmap source) 
{ 
    return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
        source.GetHbitmap(), 
        IntPtr.Zero, 
        Int32Rect.Empty, 
        BitmapSizeOptions.FromEmptyOptions()); 
} 

public static Bitmap BitmapFromSource(BitmapSource bitmapsource) 
{ 
    Bitmap bitmap; 
    using (var outStream = new MemoryStream()) 
    { 
     BitmapEncoder enc = new BmpBitmapEncoder(); 
     enc.Frames.Add(BitmapFrame.Create(bitmapsource)); 
     enc.Save(outStream); 
     bitmap = new Bitmap(outStream); 
    } 
    return bitmap; 
} 

Funciona perfectamente para mí.

+0

¡Lo intenté durante años! Muchas gracias! ¡Funciona perfectamente! –

+3

Esta es una solución robusta, pero tenga en cuenta que no es tan eficiente como el mapa de bits se copia a la secuencia de memoria y luego se copia en la memoria del nuevo mapa de bits por segunda vez. Para imágenes de alta resolución, esto podría ser un problema de rendimiento. La respuesta aceptada aborda esto. – snort

+0

MSDN dice: "Debe mantener la secuencia abierta durante toda la vida del mapa de bits". La solución es clonar bitmap to new y Dispose bitmap created from stream. – Arci

1

Aquí hay un código para establecer el fondo transparente de cualquier recurso de mapa de bits dentro de un diccionario de recursos (no se usa Resources.resx a menudo en Windows.Forms age). Llamo a este método antes de InitializeComponent() - method. El ConvertBitmap de los metodos (fuente de mapa de bits) y BitmapFromSource (BitmapSource bitmapsource) se mencionan en la publicación de melvas anterior.

private void SetBitmapResourcesTransparent() 
    { 
     Image img; 
     BitmapSource bmpSource; 
     System.Drawing.Bitmap bmp; 
     foreach (ResourceDictionary resdict in Application.Current.Resources.MergedDictionaries) 
     { 
      foreach (DictionaryEntry dictEntry in resdict) 
      { 
       // search for bitmap resource 
       if ((img = dictEntry.Value as Image) is Image 
        && (bmpSource = img.Source as BitmapSource) is BitmapSource 
        && (bmp = BitmapFromSource(bmpSource)) != null) 
       { 
        // make bitmap transparent and assign it back to ressource 
        bmp.MakeTransparent(System.Drawing.Color.Magenta); 
        bmpSource = ConvertBitmap(bmp); 
        img.Source = bmpSource; 
       } 
      } 

     } 

    } 
1

Esta es limpio y rápido que la luz:

return Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, 
     Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 
Cuestiones relacionadas