我在XAML中定义了以下控件:

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

我还有一些数据存储在IntPtr中,表示BGRA 640x480图像. 对于本例,我们可以假设我从.png文件中读取图像(但这只是我可以从中获取图像数据的方法之一):

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

我认为为了更改Image控件的源,我可以使用WriteableBitmap.以下是我想出的一个完全正常工作的代码:

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;

然而,上面的代码从IntPtr(bitmapData.Scan0)到byte[](管理数组)额外复制了一份,因为imageBitmap.PixelBuffer.AsStream().Write不接受IntPtr作为参数.

有没有办法在没有多余副本的情况下做同样的事情?

附注:在WPF中,我曾经有过以下运行良好的代码,它不需要从IntPtr转换为byte[]:

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中做同样的事情

推荐答案

一边是IntPtr,另一边是Stream,因此您需要Stream实现而不是IntPtr.

您可以使用UnmanagedMemoryStream Class和自定义SafeBuffer类来实现这一点:

public sealed class IntPtrBuffer : SafeBuffer
{
    public IntPtrBuffer(IntPtr pointer, long byteLength)
        : base(false)
    {
        handle = pointer;
        Initialize((ulong)byteLength);
    }

    protected override bool ReleaseHandle() => true;
}

并像这样使用它:

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

var imageBitmap = new WriteableBitmap(bitmap.Width, bitmap.Height);

var bitmapData = bitmap.LockBits(
    new Rectangle(0, 0, bitmap.Width, bitmap.Height),
    ImageLockMode.ReadOnly, bitmap.PixelFormat
);

var byteLength = bitmapData.Height * bitmapData.Stride;
using var ums = new UnmanagedMemoryStream(new IntPtrBuffer(bitmapData.Scan0, byteLength), 0, byteLength);
using var pixels = imageBitmap.PixelBuffer.AsStream();
ums.CopyTo(pixels);

bitmap.UnlockBits(bitmapData);

this.image.Source = imageBitmap;

Csharp相关问答推荐

在Microsoft XNA框架(MonoGame)中旋转相机

AutoMapper -如何为两个不同的用例设置单个映射?

如何告诉自己创建的NuGet包在应用程序中发生了变化?

实体核心框架--HasColumnType和HasPrecision有什么不同?

在发布表单时绑定包含附加(嵌套)列表的对象列表的正确语法是什么

Select Many和默认IfEmpty内部Select Many错误工作

AsNoTrackingWithIdentitySolutions()似乎不起作用?

XUNIT是否使用测试数据的源生成器?

只有第一个LINQ.Count()语句有效

为什么我的表单在绑定到对象时提交空值?

使用C#HttpClient以多部分形式数据发送带有非ASCII文件名的文件的问题

尽管保证密钥不同,但已添加相同密钥的项(&Q;)

如何将字符串变量传递给JObject C#-无法加载文件或程序集';System.Text.Json

使用Dapper映射联接查询对象数据到使用SplitOn;

TagHelpers在新区域不起作用

为值对象编写自定义JsonConverter

使用C#和.NET 7.0无法访问Cookie中的数据

如何从Entity Framework Core中填充ListIInterface

如何在C# WinForm控件中使用Windows 10/11的黑暗主题?

为什么连接到Google OAuth2后,结果.Credential为空?