2010-02-17 7 views
35

Per quanto posso dire l'unico modo per convertire da BitmapSource al bitmap è attraverso codice non sicuro ... Ti piace questa (da Lesters WPF blog):C'è un buon modo per convertire tra BitmapSource e 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; 
    } 
} 

di fare il contrario:

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

C'è un modo più semplice nel framework? E qual è la ragione per cui non è lì (se non lo è)? Penserei che sia abbastanza utilizzabile.

Il motivo per cui ho bisogno è che utilizzo AForge per eseguire determinate operazioni dell'immagine in un'app WPF. WPF vuole mostrare BitmapSource/ImageSource ma AForge funziona su Bitmap.

+10

Per eseguire l'operazione inversa, * * * * deve ** eliminare l'handle bitmap ottenuto con 'GetHbitmap'. Questo bug è su Internet. È inspiegabile. Il mondo sta lentamente perdendo maniglie GDI; presto nuoteremo in loro! –

+0

Thx, per indicare :) – JohannesH

+2

romkyns si riferisce a questo: http://stackoverflow.com/questions/1546091/wpf-createbitmapsourcefromhbitmap-memory-leak –

risposta

54

E 'possibile fare senza l'utilizzo di codice non sicuro utilizzando Bitmap.LockBits e copiare i pixel dal BitmapSource dritto al 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

Questo funzionerebbe solo se il formato pixel è noto in precedenza, è praticamente il modo in cui sono andato e una funzione aggiuntiva per mappare tra i formati di pixel. – JohannesH

+0

Funziona con WPF? La bitmap sembra provenire da System.Drawing e utilizzata in WinForms. Tuttavia, la risorsa Bitmap viene utilizzata in WPF. – Jonas

+0

Il codice sopra riportato viene utilizzato per convertire un BitmapSource di WPF in una bitmap di Windows Form, il codice dovrebbe "funzionare" in WPF, a condizione che vengano indicati gli assembly corretti, tuttavia non sarà molto utile poiché se hai già un BitmapSource puoi usare direttamente in WPF. –

2

È questo che stai cercando?

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

Non penso che sia giusto - stai passando un puntatore a una matrice di byte dove invece si aspettava un handle Bitmap Win32. - Grazie per aver sottolineato che questa funzione esiste però, è pulito. – BrainSlugs83

27

Si può semplicemente utilizzare questi due metodi:

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; 
} 

Funziona perfettamente per me.

+0

Ci stavo provando da secoli! Grazie mille! Funziona perfettamente! –

+3

Questa è una soluzione robusta, ma attenzione che non sia efficiente come la bitmap viene copiata nello stream di memoria e quindi copiata nella memoria della nuova bitmap una seconda volta. Per le immagini ad alta risoluzione questo potrebbe essere un problema di prestazioni. La risposta accettata affronta questo. – snort

+0

MSDN dice: "È necessario mantenere il flusso aperto per tutta la vita della Bitmap." La soluzione alternativa è Clona bitmap su nuova e Dispose bitmap creata dallo stream. – Arci

1

Qui un codice per impostare lo sfondo trasparente a qualsiasi risorsa bitmap all'interno di un dizionario di risorse (non Resources.resx spesso utilizzato nell'era Windows.Forms). Chiamo questo metodo prima di InitializeComponent() - methode. I metodi 'ConvertBitmap (Bitmap source)' e BitmapFromSource (BitmapSource bitmapsource) sono menzionati in post da melvas sopra.

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

Questo è pulito e più veloci della luce:

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