2008-09-18 204 views

回答

77

感谢Hallgrim,这里是我结束了代码:

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

我也结束了在我原来的问题

+2

太棒了!你为什么不选择自己的答案作为问题的答案?你的现在好多了。 – Hallgrim 2008-09-18 21:28:04

+1

由于您的答案已被接受,因此您可以编辑答案以使其更加完整。 – 2009-05-28 05:35:34

+39

不要介意这段代码泄漏了一个HBitmap。请参阅http://stackoverflow.com/questions/1118496/using-image-control-in-wpf-to-display-system-drawing-bitmap/1118557#1118557了解修补程序 – 2009-07-13 11:54:51

10

最简单的事情是,如果你可以直接从文件制作WPF位图。

否则,您将不得不使用System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap。

6

我在一家影像供应商工作,并为我们的图像格式写了一个WPF适配器,类似于System.Drawing.Bitmap。

我写这篇KB解释给我们的客户:

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

而且有代码有没有做它。你需要用Bitmap替换AtalaImage,并且做我们正在做的等价物 - 它应该是非常简单的。

+0

谢谢楼 - 能够做到我需要的一行代码 – Kevin 2008-09-18 20:21:06

242

绑定到的BitmapSource代替的BitmapImage如何从加载它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(); 
} 
51

我知道这已被回答,但这里有几个扩展方法(用于.NET 3.0+)进行转换。 :)

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

和NativeMethods类(安抚的FxCop)

/// <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); 
} 
21

我花了一些时间来转换工作左右逢源,所以这里是我想出了两个扩展方法:

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

我来到这个问题,因为我试图做同样的事情,但在我的情况下,位图来自资源/文件。我找到了最好的解决方案是在下面的链接中描述:

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

我对这个问题的一些资源建立服食。 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

您只需通过编写自定义的BitmapSource共享两个命名空间(媒体和图纸)之间的PixelData取出。转换将立即发生并且不会分配额外的内存。如果你不想明确地创建你的位图副本,这是你想要的方法。

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 
}