Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Bitmap to BitmapSource

0.00/5 (No votes)
7 Sep 2010 3  
How to convert System.Drawing.Bitmap to System.Windows.Media.Imaging.BitmapSource

Introduction

When I started to convert my application from WinForms to WPF, I quickly reached the point where I needed to use my System.Drawing.Bitmap resources in WPF controls. But WPF uses System.Windows.Media.Imaging.BitmapSource.

The .NET Framework provides some interoperability methods to make this conversion but be careful when using them! This article will point some interesting things to know when using these methods and how you can avoid them.

Using the Code

My first attempt looked like this:

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

        return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
            bitmap.GetHbitmap(),
            IntPtr.Zero,
            Int32Rect.Empty,
            BitmapSizeOptions.FromEmptyOptions());
    }
}

The CreateBitmapSourceFromHBitmap method does all the job: it returns a managed BitmapSource, based on the provided pointer to an unmanaged bitmap and palette information.

The problem with this piece of code is the call to GetHbitmap. It will leave a dangling GDI handle unless you P/Invoke to DeleteObject():

public static class Imaging
{
    [DllImport("gdi32.dll")]
    private static extern bool DeleteObject(IntPtr hObject);

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

        IntPtr hBitmap = bitmap.GetHbitmap();

        try
        {
            return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                hBitmap,
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());
        }
        finally
        {
            DeleteObject(hBitmap);
        }
    }
}

Calling DeleteObject will release the GDI handle. This method will work perfectly for most cases. However, if you have to work in a multi-threaded environment, be aware that it is not allowed to call GetHbitmap on the same bitmap in two different threads at the same time. To avoid this, use the lock keyword to create a critical section:

public static class Imaging
{
    [DllImport("gdi32.dll")]
    private static extern bool DeleteObject(IntPtr hObject);

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

        lock (bitmap)
        {
            IntPtr hBitmap = bitmap.GetHbitmap();

            try
            {
                return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    hBitmap,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            }
            finally
            {
                DeleteObject(hBitmap);
            }
        }
    }
}

In my opinion, using DllImport is not elegant and I try to avoid it when possible. To avoid using it, you should get rid of the interoperability method and use Bitmap Decoders:

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

        using (MemoryStream memoryStream = new MemoryStream())
        {
            try
            {
                // You need to specify the image format to fill the stream. 
                // I'm assuming it is PNG
                bitmap.Save(memoryStream, ImageFormat.Png);
                memoryStream.Seek(0, SeekOrigin.Begin);

                BitmapDecoder bitmapDecoder = BitmapDecoder.Create(
                    memoryStream,
                    BitmapCreateOptions.PreservePixelFormat,
                    BitmapCacheOption.OnLoad);
                
                // This will disconnect the stream from the image completely...
                WriteableBitmap writable = 
		new WriteableBitmap(bitmapDecoder.Frames.Single());
                writable.Freeze();

                return writable;
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
}

There is still a problem with this way of doing it: this method needs to be called from the UI thread otherwise it might throw exceptions later depending on how you are using the bitmap.

public static class Imaging
{
    public static BitmapSource CreateBitmapSourceFromBitmap(Bitmap bitmap)
    {
        if (bitmap == null)
            throw new ArgumentNullException("bitmap");
                
        if (Application.Current.Dispatcher == null)
            return null; // Is it possible?
                
        try
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                // You need to specify the image format to fill the stream. 
                // I'm assuming it is PNG
                bitmap.Save(memoryStream, ImageFormat.Png);
                memoryStream.Seek(0, SeekOrigin.Begin);
                
                // Make sure to create the bitmap in the UI thread
                if (InvokeRequired)
                    return (BitmapSource)Application.Current.Dispatcher.Invoke(
                        new Func<Stream, BitmapSource>(CreateBitmapSourceFromBitmap),
                        DispatcherPriority.Normal,
                        memoryStream);
                
                return CreateBitmapSourceFromBitmap(memoryStream);
            }
        }
        catch (Exception)
        {
            return null;
        }
    }
                
    private static bool InvokeRequired
    {
        get { return Dispatcher.CurrentDispatcher != Application.Current.Dispatcher; }
    }
                
    private static BitmapSource CreateBitmapSourceFromBitmap(Stream stream)
    {
        BitmapDecoder bitmapDecoder = BitmapDecoder.Create(
            stream,
            BitmapCreateOptions.PreservePixelFormat,
            BitmapCacheOption.OnLoad);
                
        // This will disconnect the stream from the image completely...
        WriteableBitmap writable = new WriteableBitmap(bitmapDecoder.Frames.Single());
        writable.Freeze();
                
        return writable;
    }
} 

When Do You Really Need to do Conversions Like These?

As I pointed in the introduction of this article, I needed to make conversions from System.Drawing.Bitmap to System.Windows.Media.Imaging.BitmapSource because my application was sharing some resources between WinForms and WPF. In fact, I can't really think of any other situation where it would be really required to do so (if you have any, let me know).

For sure, you should not need to do these conversions when starting a WPF application from scratch. You should take a look at this article (or Google it to find tons of articles about this subject) to learn how to manage images in a WPF application.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here