Преобразование System.Drawing.Icon в System.Media.ImageSource - PullRequest
41 голосов
/ 15 июля 2009

У меня есть IntPtr, маршалированный через неуправляемую / управляемую границу, которая соответствует дескриптору значка. Преобразование его в Icon является тривиальным с помощью метода FromHandle (), и до недавнего времени это было удовлетворительным.

По сути, теперь у меня достаточно странных потоков, когда танец MTA / STA, который я исполняю, чтобы не дать хосту WinForm нарушить основной (WPF-tastic) пользовательский интерфейс приложения, слишком хрупок, чтобы его придерживаться , Итак, WinForm должен идти.

Итак, как мне получить ImageSource-версию Icon?

Обратите внимание, я пробовал ImageSourceConverter безрезультатно.

Кроме того, я могу получить базовый ресурс для некоторых , но не всех задействованных значков, и они обычно существуют вне сборки моего приложения (на самом деле, они часто существуют в неуправляемых dll).

Ответы [ 7 ]

81 голосов
/ 05 июля 2011

Простой метод преобразования без создания дополнительных объектов:

    public static ImageSource ToImageSource(this Icon icon)
    {
        ImageSource imageSource = Imaging.CreateBitmapSourceFromHIcon(
            icon.Handle,
            Int32Rect.Empty,
            BitmapSizeOptions.FromEmptyOptions());

        return imageSource;
    }
51 голосов
/ 15 июля 2009

Попробуйте это:

Icon img;

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

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

ОБНОВЛЕНИЕ : включение предложения Алекса и превращение его в метод расширения:

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

Тогда вы можете сделать:

ImageSource wpfBitmap = img.ToImageSource();
10 голосов
/ 27 октября 2010

При использовании одноразовых потоков почти всегда рекомендуется использовать блоки 'using' для принудительного освобождения ресурсов.

using (MemoryStream iconStream = new MemoryStream())
{
   icon.Save(iconStream);
   iconStream.Seek(0, SeekOrigin.Begin);

   this.TargetWindow.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconStream);
}

Где icon является источником System.Drawing.Icon, а this.TargetWindow является целевым System.Windows.Window.

9 голосов
/ 28 августа 2009
MemoryStream iconStream = new MemoryStream();
myForm.Icon.Save(iconStream);
iconStream.Seek(0, SeekOrigin.Begin);
_wpfForm.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconStream);
1 голос
/ 04 июля 2016

С учетом вышесказанного, я создал иконки высочайшего качества для себя. Загрузка значков из байтового массива. Я использую кэш-загрузку, потому что если вы этого не сделаете, вы получите исключение при удалении потока памяти.

   internal static ImageSource ToImageSource(this byte[] iconBytes)
    {
        if (iconBytes == null)
            throw new ArgumentNullException(nameof(iconBytes));
        using (var ms = new MemoryStream(iconBytes))
        {
            return BitmapFrame.Create(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
        }
    }
0 голосов
/ 09 мая 2016

Пример похож на пример, настроенный только из сценариев использования разработчика ...

    [DllImport("shell32.dll")]
    public static extern IntPtr ExtractIcon(IntPtr hInst, string file, int nIconIndex);

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool DestroyIcon(IntPtr hIcon);

    /// <summary>
    /// Gets application icon from main .exe.
    /// </summary>
    /// <param name="setToObject">object to which to set up icon</param>
    /// <param name="bAsImageSource">true if get it as "ImageSource" (xaml technology), false if get it as "Icon" (winforms technology)</param>
    /// <returns>true if successful.</returns>
    public bool GetIcon(object setToObject, bool bAsImageSource)
    {
        String path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        path = Path.Combine(path, "yourmainexecutableName.exe");
        int iIconIndex = 0;

        // If your application contains multiple icons, then
        // you could change iIconIndex here.

        object o2set = null;
        IntPtr hIcon = ExtractIcon(IntPtr.Zero, path, iIconIndex);
        if (hIcon == IntPtr.Zero)
            return false;

        Icon icon = (Icon)Icon.FromHandle(hIcon);
        if (bAsImageSource)
        {
            o2set = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                icon.ToBitmap().GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, 
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
        } else {
            icon = (Icon)icon.Clone();
        }

        DestroyIcon(hIcon);
        setToObject.GetType().GetProperty("Icon").SetValue(setToObject, o2set);
        return true;
    } //GetIcon
0 голосов
/ 22 сентября 2015

Существует действительно простое решение этой проблемы.

Шаги:

(1) добавить изображение к ресурсам в обозревателе решений -> resources.resx (2) измените свойства изображения в каталоге «Resources» в обозревателе решений и измените «Build action» на «Resource»

В xaml добавить следующее ...

Icon = "resources / name of image" (где "name of image" - это имя изображения, которое вы добавили в ресурсы - см. Пункт (1).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...