35

I need to convert a System.Drawing.Bitmap into System.Windows.Media.ImageSource class in order to bind it into a HeaderImage control of a WizardPage (Extended WPF toolkit). The bitmap is set as a resource of the assembly I write. It is being referenced like that:

public Bitmap GetBitmap
{
   get
   {
      Bitmap bitmap = new Bitmap(Resources.my_banner);
      return bitmap;
   }
}

public ImageSource HeaderBitmap
{
   get
   {
      ImageSourceConverter c = new ImageSourceConverter();
      return (ImageSource)c.ConvertFrom(GetBitmap);
   }
}

The converter was found by me here. I get a NullReferenceException at

return (ImageSource) c.ConvertFrom(Resources.my_banner);

How can I initialize ImageSource in order to avoid this exception? Or is there another way? I want to use it afterwards like:

<xctk:WizardPage x:Name="StartPage" Height="500" Width="700"
                 HeaderImage="{Binding HeaderBitmap}" 
                 Enter="StartPage_OnEnter"

Thanks in advance for any answers.

thatguy
  • 21,059
  • 6
  • 30
  • 40
user3489135
  • 351
  • 1
  • 3
  • 5
  • See here: [What is a NullReferenceException and how do I fix it?](http://stackoverflow.com/q/4660142/1136211) – Clemens Oct 08 '14 at 15:51

6 Answers6

50

For others, this works:

    //If you get 'dllimport unknown'-, then add 'using System.Runtime.InteropServices;'
    [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DeleteObject([In] IntPtr hObject);

    public ImageSource ImageSourceFromBitmap(Bitmap bmp)
    {
        var handle = bmp.GetHbitmap();
        try
        {
            return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        }
        finally { DeleteObject(handle); }               
    }
maxp
  • 24,209
  • 39
  • 123
  • 201
dethSwatch
  • 1,152
  • 1
  • 10
  • 18
  • 4
    You are my hero. Used this to make an extension for the Bitmap class and it worked fantastic. Nice work. – ARidder101 Sep 23 '16 at 20:07
  • 1
    @ARidder101 I'm sure I got this from someone else fwiw. – dethSwatch Sep 24 '16 at 16:24
  • This approach gives very low quality transparency. Mike Strobel's answer below (https://stackoverflow.com/a/26261562/418362) is much better and does not require any interop. – Artfunkel Sep 04 '18 at 11:21
  • Let me know what happen when I didn't call DeleteObject(handle). I've had a problem about this. thank you. – Masuri Jun 03 '19 at 06:29
  • back in .NET 2.0 days on windows XP, there was a limit of 10.000 handles that couild be opened at the same time. The machine froze when that limit was reached. - So not calling the deletes, means you'll leak a handle. .NET properbly cleans it up somewhere, but you'll most likely get a performance hit.' – kfn Apr 14 '21 at 09:25
32

For the benefit of searchers, I created a quick converter based on a this more detailed solution.

No problems so far.

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

namespace XYZ.Helpers
{
    public class ConvertBitmapToBitmapImage
    {
        /// <summary>
        /// Takes a bitmap and converts it to an image that can be handled by WPF ImageBrush
        /// </summary>
        /// <param name="src">A bitmap image</param>
        /// <returns>The image as a BitmapImage for WPF</returns>
        public BitmapImage Convert(Bitmap src)
        {
            MemoryStream ms = new MemoryStream();
            ((System.Drawing.Bitmap)src).Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
            BitmapImage image = new BitmapImage();
            image.BeginInit();
            ms.Seek(0, SeekOrigin.Begin);
            image.StreamSource = ms;
            image.EndInit();
            return image;
        }
    }
}
JsAndDotNet
  • 16,260
  • 18
  • 100
  • 123
14

I do not believe that ImageSourceConverter will convert from a System.Drawing.Bitmap. However, you can use the following:

public static BitmapSource CreateBitmapSourceFromGdiBitmap(Bitmap bitmap)
{
    if (bitmap == null)
        throw new ArgumentNullException("bitmap");

    var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);

    var bitmapData = bitmap.LockBits(
        rect,
        ImageLockMode.ReadWrite,
        PixelFormat.Format32bppArgb);

    try
    {
        var size = (rect.Width * rect.Height) * 4;

        return BitmapSource.Create(
            bitmap.Width,
            bitmap.Height,
            bitmap.HorizontalResolution,
            bitmap.VerticalResolution,
            PixelFormats.Bgra32,
            null,
            bitmapData.Scan0,
            size,
            bitmapData.Stride);
    }
    finally
    {
        bitmap.UnlockBits(bitmapData);
    }
}

This solution requires the source image to be in Bgra32 format; if you are dealing with other formats, you may need to add a conversion.

Mike Strobel
  • 25,075
  • 57
  • 69
13

dethSwatch - Thank you for your answer above! It helped tremendously! After implementing it I was getting the desired behavior but I found I was getting a memory/handle issue in another section of my program. I changed the code as follows, making it a little more verbose and the issue went away. Thank you again!

    [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DeleteObject([In] IntPtr hObject);

    public ImageSource ImageSourceForBitmap(Bitmap bmp)
    {
        var handle = bmp.GetHbitmap();
        try
        {
            ImageSource newSource = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());

            DeleteObject(handle);
            return newSource;
        }
        catch (Exception ex)
        {
            DeleteObject(handle);
            return null;
        }
    }
user8366267
  • 151
  • 1
  • 4
  • A bit more pretty variant of your :) ``` var handle = bmp.GetHbitmap(); try { return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } catch { return null; } finally { Win32.DeleteObject(handle); } ``` – Vincent Oct 04 '19 at 08:11
5
void Draw()
{
    System.Drawing.Bitmap bmp = new Bitmap();
    ...
    Image img = new Image();
    img.Source = BitmapToImageSource(bmp)
 }


private BitmapImage BitmapToImageSource(System.Drawing.Bitmap bitmap)
{
    using (MemoryStream memory = new MemoryStream())
    {
        bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);
        memory.Position = 0;
        BitmapImage bitmapimage = new BitmapImage();
        bitmapimage.BeginInit();
        bitmapimage.StreamSource = memory;
        bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapimage.EndInit();
        return bitmapimage;
    }
}
Timo Schett
  • 51
  • 1
  • 2
4

The simpliest solution for me:

ImageBrush myBrush = new ImageBrush();
var bitmap = System.Drawing.Image.FromFile("pic1.bmp");
Bitmap bitmap = new System.Drawing.Bitmap(image);//it is in the memory now
var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(),IntPtr.Zero,Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
myBrush.ImageSource = bitmapSource;
cover.MainGrid.Background = myBrush;
cover.Show();
bitmap.Dispose();
vinsa
  • 1,132
  • 12
  • 25