Last active
September 21, 2025 17:13
-
-
Save ynkdir/40168f3031f640295648c26638e28226 to your computer and use it in GitHub Desktop.
WinUI3 example for SoftwareBitmap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# How to show a PIL image in WinUI | |
import io | |
from PIL import Image | |
from win32more.Microsoft.UI.Xaml.Media.Imaging import BitmapImage, SoftwareBitmapSource | |
from win32more.Microsoft.Windows.Storage.Pickers import FileOpenPicker | |
from win32more.Windows.Graphics.Imaging import ( | |
BitmapAlphaMode, | |
BitmapBufferAccessMode, | |
BitmapPixelFormat, | |
SoftwareBitmap, | |
) | |
from win32more.Windows.Storage.Streams import DataWriter, InMemoryRandomAccessStream | |
from win32more.Windows.Win32.System.WinRT import IMemoryBufferByteAccess | |
from win32more import FAILED, POINTER, Byte, UInt32, WinError | |
from win32more.appsdk.xaml import XamlApplication, XamlLoader | |
class App(XamlApplication): | |
def InitializeComponent(self): | |
# With WindowsAppSDK1.8.0, creating XamlControlsResources() fails. | |
# Disable default app.xaml loading. | |
pass | |
def OnLaunched(self, args): | |
self._window = XamlLoader.Load( | |
self, | |
"""<?xml version="1.0" encoding="utf-8"?> | |
<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:controls="using:Microsoft.UI.Xaml.Controls"> | |
<StackPanel> | |
<Button x:Name="Button1" Click="Button1_Click" Content="SoftwareBitmap" /> | |
<Button x:Name="Button2" Click="Button2_Click" Content="BitmapImage" /> | |
<Image x:Name="Image1" Width="500" Height="500" /> | |
</StackPanel> | |
</Window> | |
""", | |
) | |
self._window.Activate() | |
async def Button1_Click(self, sender, e): | |
path = await self._pick_file() | |
if path is None: | |
return | |
image = Image.open(path) | |
self.Image1.Width = image.width | |
self.Image1.Height = image.height | |
self.Image1.Source = await self.create_software_bitmap_from_pil_image(image) | |
async def Button2_Click(self, sender, e): | |
path = await self._pick_file() | |
if path is None: | |
return | |
image = Image.open(path) | |
self.Image1.Width = image.width | |
self.Image1.Height = image.height | |
self.Image1.Source = await self.create_bitmap_from_pil_image(image) | |
async def _pick_file(self): | |
picker = FileOpenPicker(self._window.AppWindow.Id) | |
r = await picker.PickSingleFileAsync() | |
if not r: | |
return None | |
return r.Path | |
async def create_software_bitmap_from_pil_image(self, image): | |
bitmap = SoftwareBitmap(BitmapPixelFormat.Bgra8, image.width, image.height, BitmapAlphaMode.Premultiplied) | |
with bitmap.LockBuffer(BitmapBufferAccessMode.Write) as buffer: | |
with buffer.CreateReference() as reference: | |
byte_access = reference.as_(IMemoryBufferByteAccess) | |
p = POINTER(Byte)() | |
n = UInt32() | |
hr = byte_access.GetBuffer(p, n) | |
if FAILED(hr): | |
raise WinError(hr) | |
for i, (r, g, b, a) in enumerate(image.convert("RGBA").getdata()): | |
p[i * 4] = b | |
p[i * 4 + 1] = g | |
p[i * 4 + 2] = r | |
p[i * 4 + 3] = a | |
source = SoftwareBitmapSource() | |
await source.SetBitmapAsync(bitmap) | |
return source | |
async def create_bitmap_from_pil_image(self, image): | |
buf = io.BytesIO() | |
image.save(buf, format="PNG") | |
stream = InMemoryRandomAccessStream() | |
writer = DataWriter(stream) | |
writer.WriteBytes(buf.getvalue()) | |
await writer.StoreAsync() | |
await writer.FlushAsync() | |
stream.Seek(0) | |
bitmap = BitmapImage() | |
bitmap.SetSource(stream) | |
return bitmap | |
XamlApplication.Start(App) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# WinUI3 example for SoftwareBitmap. | |
from win32more import FAILED, POINTER, Byte, UInt32, WinError | |
from win32more.appsdk.xaml import XamlApplication, XamlLoader | |
from win32more.Microsoft.UI.Xaml.Media.Imaging import SoftwareBitmapSource | |
from win32more.Windows.Graphics.Imaging import ( | |
BitmapAlphaMode, | |
BitmapBufferAccessMode, | |
BitmapPixelFormat, | |
SoftwareBitmap, | |
) | |
from win32more.Windows.Win32.System.WinRT import IMemoryBufferByteAccess | |
class App(XamlApplication): | |
def OnLaunched(self, args): | |
self._window = XamlLoader.Load( | |
self, | |
"""<?xml version="1.0" encoding="utf-8"?> | |
<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:controls="using:Microsoft.UI.Xaml.Controls"> | |
<StackPanel> | |
<Button x:Name="Button1" Click="Button1_Click" Content="Red" /> | |
<Button x:Name="Button2" Click="Button2_Click" Content="Blue" /> | |
<Image x:Name="Image1" Width="100" Height="100" /> | |
</StackPanel> | |
</Window> | |
""", | |
) | |
self._window.Activate() | |
async def Button1_Click(self, sender, e): | |
bitmap = self.create_software_bitmap(100, 100, 255, 0, 0) | |
source = SoftwareBitmapSource() | |
await source.SetBitmapAsync(bitmap) | |
self.Image1.Source = source | |
async def Button2_Click(self, sender, e): | |
bitmap = self.create_software_bitmap(100, 100, 0, 0, 255) | |
source = SoftwareBitmapSource() | |
await source.SetBitmapAsync(bitmap) | |
self.Image1.Source = source | |
def create_software_bitmap(self, width, height, r, g, b): | |
bitmap = SoftwareBitmap(BitmapPixelFormat.Bgra8, width, height, BitmapAlphaMode.Premultiplied) | |
with bitmap.LockBuffer(BitmapBufferAccessMode.Write) as buffer: | |
with buffer.CreateReference() as reference: | |
byte_access = reference.as_(IMemoryBufferByteAccess) | |
p = POINTER(Byte)() | |
n = UInt32() | |
hr = byte_access.GetBuffer(p, n) | |
if FAILED(hr): | |
raise WinError(hr) | |
for i in range(0, n.value, 4): | |
p[i] = b | |
p[i + 1] = g | |
p[i + 2] = r | |
p[i + 3] = 255 | |
return bitmap | |
XamlApplication.Start(App) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment