Load a WPF BitmapImage from a System.Drawing.Bitmap

前端 未结 10 2040
天涯浪人
天涯浪人 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:28
    // 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 讨论(0)
  • 2020-11-22 05:32

    You can just share the pixeldata between a both namespaces ( Media and Drawing) by writing a custom bitmapsource. The conversion will happen immediately and no additional memory will be allocated. If you do not want to explicitly create a copy of your Bitmap this is the method you want.

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

    I came to this question because I was trying to do the same, but in my case the Bitmap is from a resource/file. I found the best solution is as described in the following link:

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

    Thanks to Hallgrim, here is the code I ended up with:

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

    I also ended up binding to a BitmapSource instead of a BitmapImage as in my original question

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