Load a WPF BitmapImage from a System.Drawing.Bitmap

前端 未结 10 2039
天涯浪人
天涯浪人 2020-11-22 04:39

I have an instance of a System.Drawing.Bitmap and would like to make it available to my WPF app in the form of a System.Windows.Media.Imaging.BitmapImage<

相关标签:
10条回答
  • 2020-11-22 05:08

    My take on this built from a number of resources. 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;
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 05:09

    It took me some time to get the conversion working both ways, so here are the two extension methods I came up with:

    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;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 05:11

    The easiest thing is if you can make the WPF bitmap from a file directly.

    Otherwise you will have to use System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap.

    0 讨论(0)
  • 2020-11-22 05:18

    How about loading it from 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();
    }
    
    0 讨论(0)
  • 2020-11-22 05:24

    I know this has been answered, but here are a couple of extension methods (for .NET 3.0+) that do the conversion. :)

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

    and the NativeMethods class (to appease 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);
    }
    
    0 讨论(0)
  • 2020-11-22 05:24

    I work at an imaging vendor and wrote an adapter for WPF to our image format which is similar to a System.Drawing.Bitmap.

    I wrote this KB to explain it to our customers:

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

    And there is code there that does it. You need to replace AtalaImage with Bitmap and do the equivalent thing that we are doing -- it should be pretty straightforward.

    0 讨论(0)
提交回复
热议问题