Загрузите BitmapImage WPF из System.Drawing.Bitmap

У меня есть экземпляр System.Drawing.Bitmap и хотел бы сделать его доступным для моего приложения WPF в виде System.Windows.Media.Imaging.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(); } 

Благодаря Hallgrim, вот код, в котором я закончил:

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

Я также оказался привязан к BitmapSource вместо BitmapImage, как в моем первоначальном вопросе

Я знаю, на это был дан ответ, но вот несколько методов расширения (для .NET 3.0+), которые делают преобразование. 🙂

  ///  /// Converts a  into a WPF . ///  /// The source image. /// A BitmapSource 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; } ///  /// Converts a  into a WPF . ///  /// Uses GDI to do the conversion. Hence the call to the marshalled DeleteObject. ///  /// The source bitmap. /// A BitmapSource 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; } 

и class NativeMethods (чтобы успокоить FxCop)

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

Мне потребовалось некоторое время, чтобы преобразование работало в обоих направлениях, так что вот два метода расширения, которые я придумал:

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

Самое простое, если вы можете сделать bitmap WPF из файла напрямую.

В противном случае вам придется использовать System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap.

 // at class level; [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); // https://stackoverflow.com/a/1546121/194717 ///  /// Converts a  into a WPF . ///  /// Uses GDI to do the conversion. Hence the call to the marshalled DeleteObject. ///  /// The source bitmap. /// A BitmapSource 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; } 

Я работаю с поставщиком изображений и написал для WPF адаптер для нашего формата изображения, который похож на System.Drawing.Bitmap.

Я написал этот KB, чтобы объяснить это нашим клиентам:

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

И там есть код, который делает это. Вам нужно заменить AtalaImage на Bitmap и сделать то же самое, что мы делаем – это должно быть довольно просто.

Я беру на себя это, исходя из ряда ресурсов. https://stackoverflow.com/a/7035036 https://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; } } } } 

Я пришел к этому вопросу, потому что я пытался сделать то же самое, но в моем случае Bitmap – это ресурс / файл. Я нашел лучшее решение, как описано в следующей ссылке:

http://sofru.miximages.com/c%23/cherries_larger.jpg“,UriKind.RelativeOrAbsolute); bi.EndInit(); // Set the image source. simpleImage.Source = bi;

Вы можете просто поделиться пиксельными координатами между обоими пространствами имен (Media и Drawing), написав собственный битмапссурс. Преобразование произойдет немедленно, и никакая дополнительная память не будет выделена. Если вы не хотите явно создавать копию своего растрового изображения, это тот метод, который вы хотите.

 class SharedBitmapSource : BitmapSource, IDisposable { #region Public Properties ///  /// I made it public so u can reuse it and get the best our of both namespaces ///  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 } 
  • Сделать WPF Image load async
  • Передача двух параметров команды с использованием привязки WPF
  • ItemPropertyChanged не работает на наблюдаемомколлекции.Почему?
  • Как привязать таблицу в наборе данных к datagrid WPF в C # и XAML
  • ElementName привязка из MenuItem в ContextMenu
  • Как отображать элементы в Canvas через Binding
  • Нужно форматировать даты в динамически построенных WPF DataGrid
  • Приложение WPF, в котором есть только значок в трее
  • Доступ к интерфейсу пользовательского интерфейса (Main) безопасно в WPF
  • В чем разница между StaticResource и DynamicResource в WPF?
  • Выберите несколько элементов из DataGrid в проекте MVVM MVPM
  • Давайте будем гением компьютера.