Преобразование System.Drawing.Icon в System.Media.ImageSource
У меня есть IntPtr, маршалированный по неуправляемой/управляемой границе, которая соответствует значку Handle. Преобразование его в значок тривиально с помощью метода FromHandle(), и это было удовлетворительно до недавнего времени.
В принципе, у меня сейчас довольно много странностей, когда тандем MTA/STA, который я играл, чтобы поддерживать WinForm в нарушении основного (WPF-tastic) интерфейса приложения, слишком хрупкий, чтобы придерживаться, Итак, WinForm должен уйти.
Итак, как я могу получить версию IconSource значка?
Заметьте, я пробовал ImageSourceConverter безрезультатно.
В стороне, я могу получить базовый ресурс для некоторых, но не для всех значков, и они вообще существуют вне моей сборки приложения (фактически, они часто существуют в неуправляемых dll's).
Ответы
Ответ 1
Попробуйте следующее:
Icon img;
Bitmap bitmap = img.ToBitmap();
IntPtr hBitmap = bitmap.GetHbitmap();
ImageSource wpfBitmap =
Imaging.CreateBitmapSourceFromHBitmap(
hBitmap, IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
UPDATE. Включить предложение Alex и сделать его методом расширения:
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();
Ответ 2
Простой способ преобразования без создания каких-либо дополнительных объектов:
public static ImageSource ToImageSource(this Icon icon)
{
ImageSource imageSource = Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return imageSource;
}
Ответ 3
При использовании одноразовых потоков почти всегда рекомендуется использовать блоки "использования" для принудительного освобождения ресурсов.
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.
Ответ 4
MemoryStream iconStream = new MemoryStream();
myForm.Icon.Save(iconStream);
iconStream.Seek(0, SeekOrigin.Begin);
_wpfForm.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconStream);
Ответ 5
Взятие из вышеизложенного это создало высочайшее качество иконок для себя. Загрузка значков из массива байтов. Я использую кеш-память, потому что, если вы этого не сделаете, вы получите удаленное исключение, когда вы удалите поток памяти.
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);
}
}
Ответ 6
Как-то похожий пример, только настроенный из случаев использования разработчиков...
[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
Ответ 7
Существует очень простое решение этой проблемы.
Шаги:
(1) добавить изображение в ресурсы в explorer explorer → resources.resx(2) отредактировать свойства изображения внутри каталога "Ресурсы" в проводнике решений и изменить "Настроить действие" на "Ресурс"
В xaml добавьте следующее...
Значок = "ресурсы/имя изображения" (где "имя изображения" - это имя изображения, которое вы добавили к ресурсам - см. пункт (1).