You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI 3中如何无额外拷贝将IntPtr存储的原始图像数据写入Image控件

WinUI3 避免WriteableBitmap数据额外拷贝的实现方法

问题描述

我在XAML中定义了如下Image控件:

<Image x:Name="image" Stretch="None" Width="640" Height="480"/>

同时持有存储在IntPtr中的BGRA格式640x480图像数据(示例通过读取PNG文件获取):

Bitmap bitmap = new Bitmap("image.png");

已实现通过WriteableBitmap更新Image源的代码,但会产生额外的数据拷贝(从IntPtr转存到byte[]):

int width = 640;
int height = 480;

WriteableBitmap imageBitmap = new WriteableBitmap(width, height);
Bitmap bitmap = new Bitmap("image.png");

BitmapData bitmapData = bitmap.LockBits(
    new Rectangle(0, 0, width, height),
    ImageLockMode.ReadOnly, bitmap.PixelFormat
);
               
int size = width * height * 4;
byte[] managedArray = new byte[size];
Marshal.Copy(bitmapData.Scan0, managedArray, 0, size);

bitmap.UnlockBits(bitmapData);

imageBitmap.PixelBuffer.AsStream().Write(managedArray, 0, size);

this.image.Source = imageBitmap;

由于imageBitmap.PixelBuffer.AsStream().Write不接受IntPtr参数,必须通过byte[]中转。之前在WPF中可通过WritePixels直接实现无额外拷贝操作:

imageBitmap = new WriteableBitmap(width, height, 96d, 96d, PixelFormats.Bgra32, null);

Int32Rect rect = new Int32Rect(0, 0, width, height);
imageBitmap.WritePixels(rect, bitmapData.Scan0, width * height * 4, stride);

this.image.Source = imageBitmap;

想知道WinUI3中如何实现相同的无额外拷贝操作?

解决方案

WinUI3没有提供WPF那样的WritePixels方法,但可通过**IBufferByteAccess COM接口**直接获取WriteableBitmap.PixelBuffer的原始内存指针,实现直接内存拷贝,省略byte[]中转步骤。

1. 定义IBufferByteAccess接口

首先在代码中声明该COM接口:

[ComImport]
[Guid("905a0fef-bc53-11df-8c49-001e4fc686da")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IBufferByteAccess
{
    unsafe void Buffer(out byte* value);
}

2. 无拷贝写入实现代码

启用不安全代码后,通过接口获取指针并直接拷贝:

int width = 640;
int height = 480;
int totalSize = width * height * 4; // BGRA格式每个像素4字节

WriteableBitmap imageBitmap = new WriteableBitmap(width, height);
Bitmap bitmap = new Bitmap("image.png");

BitmapData bitmapData = bitmap.LockBits(
    new Rectangle(0, 0, width, height),
    ImageLockMode.ReadOnly,
    System.Drawing.Imaging.PixelFormat.Format32bppArgb
);

try
{
    var bufferAccess = imageBitmap.PixelBuffer as IBufferByteAccess;
    unsafe
    {
        if (bufferAccess != null)
        {
            bufferAccess.Buffer(out byte* destPtr);
            // 直接从原始IntPtr拷贝到WriteableBitmap的内存区域
            Marshal.Copy(bitmapData.Scan0, new IntPtr(destPtr), 0, totalSize);
        }
    }

    imageBitmap.Invalidate();
    this.image.Source = imageBitmap;
}
finally
{
    bitmap.UnlockBits(bitmapData);
}

注意事项

  • 需在项目属性的生成选项中勾选「允许不安全代码」。
  • 确保原始图像的像素格式与WriteableBitmap默认的BGRA8格式匹配,避免格式不兼容导致的显示异常。
  • 此方法直接操作内存指针,性能优于中转byte[]的实现。

内容的提问来源于stack exchange,提问作者Bobbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 00:22:46