Convert System.Drawing.Icon to System.Media.Imagesource

Convert System.Drawing.Icon to System.Media.ImageSource

Try this:

Icon img;

Bitmap bitmap = img.ToBitmap();
IntPtr hBitmap = bitmap.GetHbitmap();

ImageSource wpfBitmap =
Imaging.CreateBitmapSourceFromHBitmap(
hBitmap, IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());

UPDATE: Incorporating Alex's suggestion and making it an extension method:

internal static class IconUtilities
{
[DllImport("gdi32.dll", SetLastError = true)]
private static extern bool DeleteObject(IntPtr hObject);

public static ImageSource ToImageSource(this Icon icon)
{
Bitmap bitmap = icon.ToBitmap();
IntPtr hBitmap = bitmap.GetHbitmap();

ImageSource wpfBitmap = Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());

if (!DeleteObject(hBitmap))
{
throw new Win32Exception();
}

return wpfBitmap;
}
}

Then you can do:

ImageSource wpfBitmap = img.ToImageSource();

How to convert icon (Bitmap) to ImageSource?

The solution suggested by Farhan Anam will work, but it's not ideal: the icon is loaded from a file, converted to a bitmap, saved to a stream and reloaded from the stream. That's quite inefficient.

Another approach is to use the System.Windows.Interop.Imaging class and its CreateBitmapSourceFromHIcon method:

private ImageSource IconToImageSource(System.Drawing.Icon icon)
{
return Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
new Int32Rect(0, 0, icon.Width, icon.Height),
BitmapSizeOptions.FromEmptyOptions());
}

private void Button_Click_1(object sender, RoutedEventArgs e)
{
using (var ico = System.Drawing.Icon.ExtractAssociatedIcon(@"C:\WINDOWS\system32\notepad.exe"))
{
image1.Source = IconToImageSource(ico);
}
}

Note the using block to dispose the original icon after you converted it. Not doing this will cause handle leaks.

How to cast a Window's icon to BitmapImage

The problem is that the cast is not happening (bi is null after executing this line) and I'm sure that the _window.Icon is not null

It's not null, but it's probably not a BitmapImage. The Window.Icon is of type ImageSource, from which BitmapImage is derived. When you set the icon in XAML, the type of the image is typically System.Windows.Media.Imaging.BitmapFrameDecode, which is an internal class derived from BitmapFrame; so it's not a BitmapImage, which is why the cast fails.


EDIT: if you just need to convert the icon to a System.Drawing.Bitmap, you don't need a BitmapImage; a BitmapSource is enough.

var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create((BitmapSource)_window.Icon));
using (var stream = new MemoryStream()))
{
encoder.Save(stream);
stream.Position = 0; // rewind the stream
var bitmap = (System.Drawing.Bitmap)System.Drawing.Image.FromStream(stream);
var icon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
}

Display Icon in WPF Image

Icons get no love in the .NET framework. You'll have to use Icon.Save() to save the icon you got into a MemoryStream. Which allows you to use the IconBitmapDecoder constructor that takes a stream.

using XAML to bind to a System.Drawing.Image into a System.Windows.Image control

Found a way I'm happy with. Using Reed Copsey's pointer and this tutorial I've wrapped the code as a IValueConverter.

Here's the converter from System.Drawing.Image to System.Windows.Media.ImageSource;

using System;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Windows.Data;

namespace System.Windows.Media
{
/// <summary>
/// One-way converter from System.Drawing.Image to System.Windows.Media.ImageSource
/// </summary>
[ValueConversion(typeof(System.Drawing.Image), typeof(System.Windows.Media.ImageSource))]
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
// empty images are empty...
if (value == null) { return null; }

var image = (System.Drawing.Image)value;
// Winforms Image we want to get the WPF Image from...
var bitmap = new System.Windows.Media.Imaging.BitmapImage();
bitmap.BeginInit();
MemoryStream memoryStream = new MemoryStream();
// Save to a memory stream...
image.Save(memoryStream, ImageFormat.Bmp);
// Rewind the stream...
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
return bitmap;
}

public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
}
}

Then you need to bring the image converter into XAML as a resource;

xmlns:med="clr-namespace:System.Windows.Media"
...

<ListView.Resources>
<med:ImageConverter x:Key="imageConverter" />
</ListView.Resources>

Then you can use it in XAML to bind directly to the Image, using the new converter;

<Image Source="{ Binding Path=Image, Converter={StaticResource imageConverter} }" />


Related Topics



Leave a reply



Submit