Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Last active May 30, 2026 17:30
Show Gist options
  • Select an option

  • Save ynkdir/f1482fddbeed13961f7a9b20962ed648 to your computer and use it in GitHub Desktop.

Select an option

Save ynkdir/f1482fddbeed13961f7a9b20962ed648 to your computer and use it in GitHub Desktop.
Icon Resource Viewer
# /// script
# dependencies = ["win32more"]
# ///
from ctypes import POINTER
from win32more import FAILED, Byte, List, UInt32, WinError
from win32more.Microsoft.UI.Xaml.Media.Imaging import WriteableBitmap
from win32more.Microsoft.Windows.Storage.Pickers import FileOpenPicker
from win32more.Windows.Win32.Graphics.Imaging import (
CLSID_WICImagingFactory,
GUID_WICPixelFormat32bppBGRA,
IWICBitmap,
IWICFormatConverter,
IWICImagingFactory,
WICBitmapDitherTypeNone,
WICBitmapPaletteTypeCustom,
WICRect,
)
from win32more.Windows.Win32.System.Com import CLSCTX_INPROC_SERVER, CoCreateInstance
from win32more.Windows.Win32.System.WinRT import IBufferByteAccess
from win32more.Windows.Win32.UI.Shell import ExtractIconExW
from win32more.Windows.Win32.UI.WindowsAndMessaging import HICON, DestroyIcon
from win32more.winui3 import XamlApplication, XamlLoader
class App(XamlApplication):
xaml = """
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls">
<Grid x:Name="_grid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<muxc:MenuBar Grid.Row="0">
<muxc:MenuBarItem Title="File">
<muxc:MenuFlyoutItem Text="Open" Click="_File_Open_Click" />
</muxc:MenuBarItem>
</muxc:MenuBar>
<TextBlock x:Name="TextBlock1" Grid.Row="1"></TextBlock>
<GridView x:Name="GridView1" Grid.Row="2">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Width="100" Height="100">
<TextBlock Text="{Binding id}" />
<Image Width="{Binding width}" Height="{Binding height}" Source="{Binding bitmap}" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
</Window>
"""
def OnLaunched(self, args):
self._window = XamlLoader.Load(self, self.xaml)
self._window.Title = "Icon Resource Viewer"
self._window.Activate()
self._items = List()
self.GridView1.ItemsSource = self._items
async def _File_Open_Click(self, sender, args):
picker = FileOpenPicker(self._window.AppWindow.Id)
picker.FileTypeFilter.ReplaceAll([".exe", ".dll"])
result = await picker.PickSingleFileAsync()
if result is None:
# canceled
return
self.TextBlock1.Text = result.Path
self._items[:] = self._load_icon_resource(result.Path)
def _load_icon_resource(self, path):
icon_large, icon_small = self._extract_icon(path)
items = []
for i in range(len(icon_large)):
bitmap = self._create_bitmap_from_hicon(icon_large[i])
width = min(64, bitmap.PixelWidth)
height = min(64, bitmap.PixelHeight)
items.append({"id": i, "bitmap": bitmap, "width": width, "height": height})
DestroyIcon(icon_large[i])
DestroyIcon(icon_small[i])
return items
def _extract_icon(self, path):
UINT_MAX = 0xFFFFFFFF
number_of_icons = ExtractIconExW(path, -1, None, None, 0)
if number_of_icons == UINT_MAX:
raise WinError()
if number_of_icons == 0:
return [], []
icon_large = (HICON * number_of_icons)()
icon_small = (HICON * number_of_icons)()
result = ExtractIconExW(path, 0, icon_large, icon_small, number_of_icons)
if result == -1:
raise WinError()
return icon_large, icon_small
def _create_bitmap_from_hicon(self, hicon):
wic_factory = IWICImagingFactory(own=True)
r = CoCreateInstance(CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER, IWICImagingFactory._iid_, wic_factory)
if FAILED(r):
raise WinError(r)
wic_bitmap = IWICBitmap(own=True)
r = wic_factory.CreateBitmapFromHICON(hicon, wic_bitmap)
if FAILED(r):
raise WinError(r)
converter = IWICFormatConverter(own=True)
r = wic_factory.CreateFormatConverter(converter)
if FAILED(r):
raise WinError(r)
r = converter.Initialize(
wic_bitmap, GUID_WICPixelFormat32bppBGRA, WICBitmapDitherTypeNone, None, 0, WICBitmapPaletteTypeCustom
)
if FAILED(r):
raise WinError(r)
c_width = UInt32()
c_height = UInt32()
r = wic_bitmap.GetSize(c_width, c_height)
if FAILED(r):
raise WinError(r)
width = c_width.value
height = c_height.value
wb = WriteableBitmap(width, height)
pixel_buffer = wb.PixelBuffer.as_(IBufferByteAccess)
bitmap_data = POINTER(Byte)()
r = pixel_buffer.Buffer(bitmap_data)
if FAILED(r):
raise WinError(r)
rc = WICRect(0, 0, width, height)
stride = width * 4
buffer_size = stride * height
r = converter.CopyPixels(rc, stride, buffer_size, bitmap_data)
if FAILED(r):
raise WinError(r)
return wb
if __name__ == "__main__":
XamlApplication.Start(App)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment