2010-02-17 60 views
35

至于我可以告诉从的BitmapSource转换为位图的唯一途径是通过不安全的代码......像这样(从Lesters WPF blog):有没有一种很好的方式来转换BitmapSource和位图?

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

要反过来做:

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

在框架中有更简单的方法吗?它不在那里的原因是什么(如果不是)?我认为这是相当有用的。

我需要它的原因是因为我使用AForge在WPF应用程序中执行某些图像操作。 WPF希望显示BitmapSource/ImageSource,但是AForge在位图上工作。

+10

要做相反的事情,你*必须**删除你用'GetHbitmap'得到的位图句柄。这个错误遍布互联网。这是不可修复的。世界正在缓慢泄漏GDI手柄;我们很快就会在他们身上游泳! – 2011-12-31 04:25:10

+0

Thx,指出:) – JohannesH 2012-01-03 10:22:28

+2

romkyns指的是这个:http://stackoverflow.com/questions/1546091/wpf-createbitmapsourcefromhbitmap-memory-leak – 2012-04-26 21:24:44

回答

54

这是可以做到不使用不安全的代码使用Bitmap.LockBitsBitmapSource像素直接复制到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

只有像素格式是事先知道的,它才会起作用,它与我一起使用的方式以及在像素格式之间映射的附加功能非常相似。 – JohannesH 2010-05-26 20:43:26

+0

这是适用于WPF的?位图似乎来自System.Drawing并在WinForms中使用。 尽管在WPF中使用了BitmapSource。 – Jonas 2014-05-09 09:41:42

+0

上面的代码用于将WPF BitmapSource转换为Windows窗体位图,如果正确的程序集被引用,代码应该在WPF中“工作”,但它不会非常有用,因为如果您已经有了可以使用的BitmapSource它直接在WPF中。 – 2014-05-09 09:49:30

2

这是你要找的吗?

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

我不认为这是正确的 - 你正在传递一个指向字节数组的指针,而它指向的是一个Win32位图句柄。 - 谢谢你指出这个函数存在,但它很整洁。 – BrainSlugs83 2013-11-05 06:01:34

27

你可以使用这两种方法:

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

它适用于我。

+0

我正在尝试这个年龄!非常感谢!完美的作品! – 2014-09-12 07:10:55

+3

这是一个强大的解决方案,但要注意它不如位图复制到内存流那么高效,然后再次复制到新位图的内存中。对于高分辨率图像,这可能是性能问题。接受的答案解决这个问题。 – snort 2015-02-20 17:37:25

+0

MSDN说:“您必须保持该流在Bitmap的生命周期中打开。”解决方法是将新的克隆位图和从流创建的Dispose位图。 – Arci 2015-03-04 15:19:56

1

这里是一个代码,用于设置资源字典中任何位图资源的透明背景(而不是Windows.Forms age中常用的Resources.resx)。我在InitializeComponent()方法之前调用这个方法。方法的'ConvertBitmap(Bitmap source)'和BitmapFromSource(BitmapSource bitmapsource)在上面的melvas中提到。

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

这是整洁得比光还快:

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