我有一个包含RGBA编码图像的C#字节数组.在
WPF中显示此图像的最佳方法是什么?
一种选择是从字节数组创建一个BitmapSource并将其附加到Image控件.但是,创建一个BitmapSource需要一个用于RGBA32的PixelFormat,这在Windows中似乎不可用.
byte[] buffer = new byte[] { 25,166,255,90,120,255 }; BitmapSource.Create(2,1,96d,PixelFormats.Bgra32,null,buffer,4 * 2);
我绝对不想在我的字节数组中交换像素.
解决方法
在深入研究WIC的细节之前,您可以考虑将字节交换封装在一个简单的自定义BitmapSource中,如下所示.它采用RGBA字节数组并在重写的CopyPixels方法中交换像素字节以生成PBGRA缓冲区.
您可以通过提供RGBA缓冲区和位图宽度来简单地创建此自定义BitmapSource的实例
var buffer = new byte[] { 25,255 }; var bitmapSource = new RgbaBitmapSource(buffer,2);
这是实施:
public class RgbaBitmapSource : BitmapSource { private byte[] rgbaBuffer; private int pixelWidth; private int pixelHeight; public RgbaBitmapSource(byte[] rgbaBuffer,int pixelWidth) { this.rgbaBuffer = rgbaBuffer; this.pixelWidth = pixelWidth; this.pixelHeight = rgbaBuffer.Length / (4 * pixelWidth); } public override void CopyPixels( Int32Rect sourceRect,Array pixels,int stride,int offset) { for (int y = sourceRect.Y; y < sourceRect.Y + sourceRect.Height; y++) { for (int x = sourceRect.X; x < sourceRect.X + sourceRect.Width; x++) { int i = stride * y + 4 * x; byte a = rgbaBuffer[i + 3]; byte r = (byte)(rgbaBuffer[i] * a / 256); // pre-multiplied R byte g = (byte)(rgbaBuffer[i + 1] * a / 256); // pre-multiplied G byte b = (byte)(rgbaBuffer[i + 2] * a / 256); // pre-multiplied B pixels.SetValue(b,i + offset); pixels.SetValue(g,i + offset + 1); pixels.SetValue(r,i + offset + 2); pixels.SetValue(a,i + offset + 3); } } } protected override Freezable CreateInstanceCore() { return new RgbaBitmapSource(rgbaBuffer,pixelWidth); } public override event EventHandler<DownloadProgressEventArgs> DownloadProgress; public override event EventHandler DownloadCompleted; public override event EventHandler<ExceptionEventArgs> DownloadFailed; public override event EventHandler<ExceptionEventArgs> DecodeFailed; public override double DpiX { get { return 96; } } public override double DpiY { get { return 96; } } public override PixelFormat Format { get { return PixelFormats.Pbgra32; } } public override int PixelWidth { get { return pixelWidth; } } public override int PixelHeight { get { return pixelHeight; } } public override double Width { get { return pixelWidth; } } public override double Height { get { return pixelHeight; } } }
正如评论中指出的那样,您可以通过实施不安全的复制操作来提高性能,这可能如下所示:
unsafe public override void CopyPixels( Int32Rect sourceRect,int offset) { fixed (byte* source = rgbaBuffer,destination = (byte[])pixels) { byte* dstPtr = destination + offset; for (int y = sourceRect.Y; y < sourceRect.Y + sourceRect.Height; y++) { for (int x = sourceRect.X; x < sourceRect.X + sourceRect.Width; x++) { byte* srcPtr = source + stride * y + 4 * x; byte a = *(srcPtr + 3); *(dstPtr++) = (byte)(*(srcPtr + 2) * a / 256); // pre-multiplied B *(dstPtr++) = (byte)(*(srcPtr + 1) * a / 256); // pre-multiplied G *(dstPtr++) = (byte)(*srcPtr * a / 256); // pre-multiplied R *(dstPtr++) = a; } } } }