如何在WinUI 3应用中显示System.Drawing.Bitmap对象
解决方法
WinUI 3 的 Image 控件仅接受派生自 Microsoft.UI.Xaml.Media.ImageSource 的类型作为源,System.Drawing.Bitmap 属于GDI+类型,无法直接赋值,需要先转换为WinUI可识别的位图对象,提供两种可直接落地的实现方案:
方案1:内存流转码(实现简单,兼容性好)
无需落地临时文件,全内存完成转换,适合绝大多数静态二维码显示场景:
- 引入所需命名空间
using System.Drawing; using System.IO; using Microsoft.UI.Xaml.Media.Imaging; using Windows.Storage.Streams;
- 编写类型转换扩展方法
public static async Task<BitmapImage> ToWinUIBitmapSourceAsync(this Bitmap gdiBitmap) { // 将GDI+位图以PNG格式写入内存流,避免画质损失 using var ms = new MemoryStream(); gdiBitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png); ms.Position = 0; // 将流读取指针重置到起始位置 // 初始化WinUI支持的位图对象 var winUiBitmap = new BitmapImage(); using var ras = ms.AsRandomAccessStream(); await winUiBitmap.SetSourceAsync(ras); return winUiBitmap; }
- 替换原有图片赋值逻辑
QRCodeGenerator qrCodeGenerator = new(); QRCodeData qrCodeData = qrCodeGenerator.CreateQrCode(associateSoftwareTokenResponse.SecretCode, QRCodeGenerator.ECCLevel.Q); QRCode qrCode = new(qrCodeData); // using语句包裹,自动释放GDI+非托管资源 using Bitmap qrCodeBitmap = qrCode.GetGraphic(20); // 给Image控件赋值 qrCodeImage.Source = await qrCodeBitmap.ToWinUIBitmapSourceAsync();
方案2:像素直接拷贝(性能更高,适合动态刷新场景)
如果需要高频更新二维码(比如时效动态码场景),可以直接拷贝像素数据,省去PNG编解码的开销,渲染延迟更低:
- 补充所需命名空间
using System.Runtime.InteropServices.WindowsRuntime;
- 编写高性能转换方法
public static WriteableBitmap ToWinUIBitmapSourceFast(this Bitmap gdiBitmap) { // 锁定GDI+位图的像素内存 var bmpData = gdiBitmap.LockBits( new Rectangle(0, 0, gdiBitmap.Width, gdiBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); // 创建同尺寸的WinUI可写位图 var writeableBmp = new WriteableBitmap(gdiBitmap.Width, gdiBitmap.Height); // 直接拷贝像素数据到WinUI位图缓冲区 writeableBmp.PixelBuffer.CopyFrom(bmpData.Scan0, (uint)(bmpData.Stride * gdiBitmap.Height)); // 解锁GDI+位图内存 gdiBitmap.UnlockBits(bmpData); return writeableBmp; }
- 调用方式(无需异步等待)
using Bitmap qrCodeBitmap = qrCode.GetGraphic(20); qrCodeImage.Source = qrCodeBitmap.ToWinUIBitmapSourceFast();
注意事项
System.Drawing.Bitmap封装了非托管GDI+资源,使用完成后必须手动释放,否则会触发内存泄漏,建议统一使用using语句包裹生命周期。- 高性能拷贝方案要求GDI+位图的像素格式为32位PARGB,QRCoder生成的默认位图符合该要求,若使用其他来源的Bitmap需要先做像素格式转换。
内容的提问来源于stack exchange,提问作者Kris
相关产品推荐
相关产品推荐

