2008-09-18 9 views
196

'dan bir WPF BitmapImage yükleyin Bir System.Drawing.Bitmap örneğim var ve bunu WPF uygulamasına bir System.Windows.Media.Imaging.BitmapImage biçiminde sunmak istiyorum.Bir System.Drawing.Bitmap

Bunun için en iyi yaklaşım hangisi olurdu?

cevap

77

sayesinde burada ben ile sona erdi kod şudur: Ben de asıl soruya

+2

Harika!Neden soruya cevap olarak kendi cevabınızı seçmiyorsunuz? Senin şu an çok daha iyi. – Hallgrim

+1

Sizinki kabul edilmiş bir cevabınız olduğundan, cevabınızı daha eksiksiz hale getirmek için düzenleyebilirsiniz. –

+39

Bu kodun bir HBitmap sızdırdığını aklınızdan çıkarmayın. Bir düzeltme için http://stackoverflow.com/questions/1118496/using-image-control-in-wpf-to-display-system-drawing-bitmap/1118557#1118557 adresine bakın. –

10

En kolay şey, WPF bitmap dosyasını doğrudan bir dosyadan yapabilmenizdir.

Aksi takdirde System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap kullanmanız gerekecektir.

6

Bir görüntüleme satıcısında çalışıyorum ve WPF için bir görüntü bağdaştırıcısına System.Drawing.Bitmap'e benzer bir bağdaştırıcı yazdım.

Ben müşterilerimize açıklamak için bu KB yazdı:

http://www.atalasoft.com/kb/article.aspx?id=10156

Ve kod var iste bu yoktur. AtalaImage'ı Bitmap ile değiştirmelisiniz ve yaptığımız işe eşdeğer bir şey yapmalısınız - oldukça basit olmalı. Hallgrím için

+0

Teşekkürler Lou - bir satırlık kodla ihtiyacım olanı yapabildi – Kevin

242

gibi yerine BitmapImage bir BitmapSource bağlanarak sona erdi

ScreenCapture = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
    bmp.GetHbitmap(), 
    IntPtr.Zero, 
    System.Windows.Int32Rect.Empty, 
    BitmapSizeOptions.FromWidthAndHeight(width, height)); 

Nasıl onu yüklemeyle ilgili memorystream?

using(MemoryStream memory = new MemoryStream()) 
{ 
    bitmap.Save(memory, ImageFormat.Png); 
    memory.Position = 0; 
    BitmapImage bitmapImage = new BitmapImage(); 
    bitmapImage.BeginInit(); 
    bitmapImage.StreamSource = memory; 
    bitmapImage.CacheOption = BitmapCacheOption.OnLoad; 
    bitmapImage.EndInit(); 
} 
+10

Bu kodu System.Drawing.Bitmap'te bir uzantı yöntemi olarak ekleyebilirsiniz, örneğin ToBitmapImage() –

+35

gibi bir resim. ImageFormat.Bmp kullanımı daha hızlı bir büyüklük sırasıdır. – RandomEngy

+20

Diğerlerinin bu kodla ilgili sorunları olması durumunda: 'bi.StreamSource' ayarlanmadan önce' ms.Seek (0, SeekOrigin.Begin); .NET 4.0 kullanıyorum. – mlsteeves

51

Bu sorunun yanıtlandığını biliyorum, ancak dönüştürmeyi gerçekleştiren birkaç uzantı yöntemi (.NET 3.0+ için). Bana iki yönde çalışan dönüşüm elde etmeyi biraz zaman aldı

/// <summary> 
/// FxCop requires all Marshalled functions to be in a class called NativeMethods. 
/// </summary> 
internal static class NativeMethods 
{ 
    [DllImport("gdi32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static extern bool DeleteObject(IntPtr hObject); 
} 
+1

Yönetilmeyen tutamaçları (ör. HBITMAP) kullanırken SafeHandles kullanmayı düşünün, bkz. Http://stackoverflow.com/questions/1546091/wpf-createbitmapsourcefromhbitmap-memory-leak/7035036#7035036 – Schneider

21

:)

 /// <summary> 
    /// Converts a <see cref="System.Drawing.Image"/> into a WPF <see cref="BitmapSource"/>. 
    /// </summary> 
    /// <param name="source">The source image.</param> 
    /// <returns>A BitmapSource</returns> 
    public static BitmapSource ToBitmapSource(this System.Drawing.Image source) 
    { 
     System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(source); 

     var bitSrc = bitmap.ToBitmapSource(); 

     bitmap.Dispose(); 
     bitmap = null; 

     return bitSrc; 
    } 

    /// <summary> 
    /// Converts a <see cref="System.Drawing.Bitmap"/> into a WPF <see cref="BitmapSource"/>. 
    /// </summary> 
    /// <remarks>Uses GDI to do the conversion. Hence the call to the marshalled DeleteObject. 
    /// </remarks> 
    /// <param name="source">The source bitmap.</param> 
    /// <returns>A BitmapSource</returns> 
    public static BitmapSource ToBitmapSource(this System.Drawing.Bitmap source) 
    { 
     BitmapSource bitSrc = null; 

     var hBitmap = source.GetHbitmap(); 

     try 
     { 
      bitSrc = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
       hBitmap, 
       IntPtr.Zero, 
       Int32Rect.Empty, 
       BitmapSizeOptions.FromEmptyOptions()); 
     } 
     catch (Win32Exception) 
     { 
      bitSrc = null; 
     } 
     finally 
     { 
      NativeMethods.DeleteObject(hBitmap); 
     } 

     return bitSrc; 
    } 

ve NativeMethods sınıf (FxCop yatıştırmak için), işte ben ile geldi iki uzatma yöntemleri şunlardır:

using System.Drawing; 
using System.Drawing.Imaging; 
using System.IO; 
using System.Windows.Media.Imaging; 

public static class BitmapConversion { 

    public static Bitmap ToWinFormsBitmap(this BitmapSource bitmapsource) { 
     using (MemoryStream stream = new MemoryStream()) { 
      BitmapEncoder enc = new BmpBitmapEncoder(); 
      enc.Frames.Add(BitmapFrame.Create(bitmapsource)); 
      enc.Save(stream); 

      using (var tempBitmap = new Bitmap(stream)) { 
       // According to MSDN, one "must keep the stream open for the lifetime of the Bitmap." 
       // So we return a copy of the new bitmap, allowing us to dispose both the bitmap and the stream. 
       return new Bitmap(tempBitmap); 
      } 
     } 
    } 

    public static BitmapSource ToWpfBitmap(this Bitmap bitmap) { 
     using (MemoryStream stream = new MemoryStream()) { 
      bitmap.Save(stream, ImageFormat.Bmp); 

      stream.Position = 0; 
      BitmapImage result = new BitmapImage(); 
      result.BeginInit(); 
      // According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed." 
      // Force the bitmap to load right now so we can dispose the stream. 
      result.CacheOption = BitmapCacheOption.OnLoad; 
      result.StreamSource = stream; 
      result.EndInit(); 
      result.Freeze(); 
      return result; 
     } 
    } 
} 
+1

Bunu kullanıyorum, ancak ImageFormat.Png kullanın. Aksi takdirde resimde siyah bir arka plan görüyorum: http://stackoverflow.com/questions/4067448/converting-image-to-bitmap-turns-background-black –

2

ben aynı şeyi yapmaya çalışıyorum çünkü ben bu soruya geldi ama benim durumumda Bitmap kaynak/dosyadan olduğunu. Bence en iyi çözüm olarak aşağıdaki bağlantıyı açıklanan bulundu: kaynakların bir dizi inşa buna

http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.aspx

// Create the image element. 
Image simpleImage = new Image();  
simpleImage.Width = 200; 
simpleImage.Margin = new Thickness(5); 

// Create source. 
BitmapImage bi = new BitmapImage(); 
// BitmapImage.UriSource must be in a BeginInit/EndInit block. 
bi.BeginInit(); 
bi.UriSource = new Uri(@"/sampleImages/cherries_larger.jpg",UriKind.RelativeOrAbsolute); 
bi.EndInit(); 
// Set the image source. 
simpleImage.Source = bi; 
9
// at class level; 
[System.Runtime.InteropServices.DllImport("gdi32.dll")] 
public static extern bool DeleteObject(IntPtr hObject); // https://stackoverflow.com/a/1546121/194717 


/// <summary> 
/// Converts a <see cref="System.Drawing.Bitmap"/> into a WPF <see cref="BitmapSource"/>. 
/// </summary> 
/// <remarks>Uses GDI to do the conversion. Hence the call to the marshalled DeleteObject. 
/// </remarks> 
/// <param name="source">The source bitmap.</param> 
/// <returns>A BitmapSource</returns> 
public static System.Windows.Media.Imaging.BitmapSource ToBitmapSource(this System.Drawing.Bitmap source) 
{ 
    var hBitmap = source.GetHbitmap(); 
    var result = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, System.Windows.Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); 

    DeleteObject(hBitmap); 

    return result; 
} 
+0

Whats "DeleteObject()"? –

+0

Bkz. Http://stackoverflow.com/questions/1546091/wpf-createbitmapsourcefromhbitmap-memory-leak – tofutim

3

My take. https://stackoverflow.com/a/7035036https://stackoverflow.com/a/1470182/360211

using System; 
using System.Drawing; 
using System.Runtime.ConstrainedExecution; 
using System.Runtime.InteropServices; 
using System.Security; 
using System.Windows; 
using System.Windows.Interop; 
using System.Windows.Media.Imaging; 
using Microsoft.Win32.SafeHandles; 

namespace WpfHelpers 
{ 
    public static class BitmapToBitmapSource 
    { 
     public static BitmapSource ToBitmapSource(this Bitmap source) 
     { 
      using (var handle = new SafeHBitmapHandle(source)) 
      { 
       return Imaging.CreateBitmapSourceFromHBitmap(handle.DangerousGetHandle(), 
        IntPtr.Zero, Int32Rect.Empty, 
        BitmapSizeOptions.FromEmptyOptions()); 
      } 
     } 

     [DllImport("gdi32")] 
     private static extern int DeleteObject(IntPtr o); 

     private sealed class SafeHBitmapHandle : SafeHandleZeroOrMinusOneIsInvalid 
     { 
      [SecurityCritical] 
      public SafeHBitmapHandle(Bitmap bitmap) 
       : base(true) 
      { 
       SetHandle(bitmap.GetHbitmap()); 
      } 

      [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
      protected override bool ReleaseHandle() 
      { 
       return DeleteObject(handle) > 0; 
      } 
     } 
    } 
} 
3

sadece özel BitmapSource yazarak hem ad (Medya ve Çizim) arasındaki pixeldata paylaşabilirsiniz. Dönüşüm hemen gerçekleşecek ve hiçbir ek bellek tahsis edilmeyecek. Bitmap'inizin bir kopyasını açıkça oluşturmak istemezseniz, istediğiniz yöntem budur.

class SharedBitmapSource : BitmapSource, IDisposable 
{ 
    #region Public Properties 

    /// <summary> 
    /// I made it public so u can reuse it and get the best our of both namespaces 
    /// </summary> 
    public Bitmap Bitmap { get; private set; } 

    public override double DpiX { get { return Bitmap.HorizontalResolution; } } 

    public override double DpiY { get { return Bitmap.VerticalResolution; } } 

    public override int PixelHeight { get { return Bitmap.Height; } } 

    public override int PixelWidth { get { return Bitmap.Width; } } 

    public override System.Windows.Media.PixelFormat Format { get { return ConvertPixelFormat(Bitmap.PixelFormat); } } 

    public override BitmapPalette Palette { get { return null; } } 

    #endregion 

    #region Constructor/Destructor 

    public SharedBitmapSource(int width, int height,System.Drawing.Imaging.PixelFormat sourceFormat) 
     :this(new Bitmap(width,height, sourceFormat)) { } 

    public SharedBitmapSource(Bitmap bitmap) 
    { 
     Bitmap = bitmap; 
    } 

    // Use C# destructor syntax for finalization code. 
    ~SharedBitmapSource() 
    { 
     // Simply call Dispose(false). 
     Dispose(false); 
    } 

    #endregion 

    #region Overrides 

    public override void CopyPixels(Int32Rect sourceRect, Array pixels, int stride, int offset) 
    { 
     BitmapData sourceData = Bitmap.LockBits(
     new Rectangle(sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height), 
     ImageLockMode.ReadOnly, 
     Bitmap.PixelFormat); 

     var length = sourceData.Stride * sourceData.Height; 

     if (pixels is byte[]) 
     { 
      var bytes = pixels as byte[]; 
      Marshal.Copy(sourceData.Scan0, bytes, 0, length); 
     } 

     Bitmap.UnlockBits(sourceData); 
    } 

    protected override Freezable CreateInstanceCore() 
    { 
     return (Freezable)Activator.CreateInstance(GetType()); 
    } 

    #endregion 

    #region Public Methods 

    public BitmapSource Resize(int newWidth, int newHeight) 
    { 
     Image newImage = new Bitmap(newWidth, newHeight); 
     using (Graphics graphicsHandle = Graphics.FromImage(newImage)) 
     { 
      graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic; 
      graphicsHandle.DrawImage(Bitmap, 0, 0, newWidth, newHeight); 
     } 
     return new SharedBitmapSource(newImage as Bitmap); 
    } 

    public new BitmapSource Clone() 
    { 
     return new SharedBitmapSource(new Bitmap(Bitmap)); 
    } 

    //Implement IDisposable. 
    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    #endregion 

    #region Protected/Private Methods 

    private static System.Windows.Media.PixelFormat ConvertPixelFormat(System.Drawing.Imaging.PixelFormat sourceFormat) 
    { 
     switch (sourceFormat) 
     { 
      case System.Drawing.Imaging.PixelFormat.Format24bppRgb: 
       return PixelFormats.Bgr24; 

      case System.Drawing.Imaging.PixelFormat.Format32bppArgb: 
       return PixelFormats.Pbgra32; 

      case System.Drawing.Imaging.PixelFormat.Format32bppRgb: 
       return PixelFormats.Bgr32; 

     } 
     return new System.Windows.Media.PixelFormat(); 
    } 

    private bool _disposed = false; 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!_disposed) 
     { 
      if (disposing) 
      { 
       // Free other state (managed objects). 
      } 
      // Free your own state (unmanaged objects). 
      // Set large fields to null. 
      _disposed = true; 
     } 
    } 

    #endregion 
} 
+0

Bir örnek gönderebilir misiniz? – shady

+1

Tam olarak aradığım şey, umarım bunu derlediğimde çalışırım = D – Greg

+0

Eğer Properties.Resources.Image dosyanız varsa ve bunu bir tuvale çizmek istiyorsanız, 133 satırlık kod alır? WPF tamam değil. –

İlgili konular