2010-02-17 19 views
35

Theo như tôi có thể nói là cách duy nhất để chuyển đổi từ BitmapSource để Bitmap là thông qua mã không an toàn ... Như thế này (từ Lesters WPF blog):Có cách nào tốt để chuyển đổi giữa BitmapSource và 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; 
    } 
} 

Để làm điều ngược lại:

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

Có cách nào dễ dàng hơn trong khung công tác không? Và lý do tại sao nó không có trong đó (nếu nó không)? Tôi nghĩ nó khá khả dụng.

Lý do tôi cần là vì tôi sử dụng AForge để thực hiện các hoạt động hình ảnh nhất định trong ứng dụng WPF. WPF muốn hiển thị BitmapSource/ImageSource nhưng AForge hoạt động trên Bitmap.

+10

Để làm ngược lại, bạn * thực sự * ** phải ** xóa xử lý bitmap bạn nhận được bằng 'GetHbitmap'. Lỗi này là tất cả trên internet. Nó không thể sửa được. Thế giới đang dần dần rò rỉ xử lý GDI; chúng tôi sẽ sớm bơi trong họ! –

+0

Thx, để chỉ ra :) – JohannesH

+2

romkyns đề cập đến điều này: http://stackoverflow.com/questions/1546091/wpf-createbitmapsourcefromhbitmap-memory-leak –

Trả lời

54

Có thể làm mà không cần sử dụng mã không an toàn bằng cách sử dụng Bitmap.LockBits và sao chép các điểm ảnh từ BitmapSource thẳng đến 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

Điều đó sẽ chỉ hoạt động nếu định dạng pixel được biết trước, nó khá giống với cách tôi đã thực hiện và chức năng bổ sung để ánh xạ giữa các định dạng pixel. – JohannesH

+0

Tính năng này có hoạt động với WPF không? Bitmap dường như đến từ System.Drawing và được sử dụng trong WinForms. BitmapSource được sử dụng trong WPF. – Jonas

+0

Đoạn mã trên được sử dụng để chuyển đổi BitmapSource của WPF thành dạng bitmap của Windows, mã sẽ "hoạt động" trong WPF, với điều kiện các assembly chính xác được tham chiếu, tuy nhiên nó sẽ không hữu ích vì nếu bạn đã có BitmapSource, bạn có thể sử dụng nó trực tiếp trong WPF. –

2

Đây có phải là nội dung bạn đang tìm kiếm không?

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

Tôi không nghĩ rằng điều này là đúng - bạn đang đi qua trong một con trỏ đến mảng byte, nơi nó thay vì mong đợi một xử lý Bitmap Win32. - Cảm ơn bạn đã chỉ ra rằng chức năng này tồn tại mặc dù, đó là gọn gàng. – BrainSlugs83

27

Bạn chỉ có thể sử dụng hai phương pháp:

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

Nó hoạt động hoàn hảo cho tôi.

+0

Tôi đã cố gắng này cho các lứa tuổi! Cảm ơn bạn rất nhiều! Hoạt động hoàn hảo! –

+3

Đây là một giải pháp mạnh mẽ, nhưng hãy cẩn thận rằng nó không hiệu quả như bitmap được sao chép vào dòng bộ nhớ sau đó được sao chép vào bộ nhớ bitmap mới lần thứ hai. Đối với hình ảnh có độ phân giải cao, đây có thể là vấn đề hiệu suất. Câu trả lời được chấp nhận giải quyết vấn đề này. – snort

+0

MSDN nói: "Bạn phải giữ luồng mở trong suốt thời gian của Bitmap." Workaround là bản sao bitmap để mới và Vứt bỏ bitmap được tạo ra từ dòng. – Arci

1

Đây là mã để đặt nền trong suốt cho bất kỳ tài nguyên bitmap nào trong một Từ điển tài nguyên (không phải Resources.resx thường được sử dụng trong Windows.Forms age). Tôi gọi methode này trước khi InitializeComponent() - methode. Các phương thức 'ConvertBitmap (nguồn bitmap)' và BitmapFromSource (bitmapSource bitmapsource) được đề cập trong bài đăng từ melvas ở trên.

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

Đây là gọn gàng và nhanh hơn ánh sáng:

return Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, 
     Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 
Các vấn đề liên quan