显示从内存RGBA图像 [英] Show RGBA image from memory

查看:147
本文介绍了显示从内存RGBA图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有包含RGBA编码的图像C#的字节数组。什么是显示在WPF这个形象的最佳方式是什么?

I have a C# byte array containing an RGBA encoded image. What is the best way to show this image in WPF?

一个办法是建立一个的BitmapSource形成字节数组,并将其连接到一个Image控件。但是,创建一个的BitmapSource需要RGBA32,这似乎并没有将Windows可用的PixelFormat。

One option would be to create a BitmapSource form the byte array and attach it to an Image control. However, creating a BitmapSource requires a PixelFormat for RGBA32, which doesn't seem to be available in Windows.

byte[] buffer = new byte[] { 25, 166, 0, 255, 90, 0, 120, 255 };
BitmapSource.Create(2, 1, 96d, 96d, PixelFormats.Bgra32, null, buffer, 4 * 2);



我绝对不希望交换的像素在我的字节数组中。

I definitely don't want to swap pixels in my byte array.

推荐答案

在你钻研WIC的细节,你可以考虑到封装字节交换在一个简单的自定义的BitmapSource如下图所示。它需要一个RGBA字节数组并交换像素字节的覆盖 CopyPixels 方法产生PBGRA缓冲区。

Before you delve into the details of WIC, you may consider to encapsulate byte swapping in a simple custom BitmapSource like shown below. It takes an RGBA byte array and swaps the pixel bytes in the overridden CopyPixels method to produce a PBGRA buffer.

你可以简单地通过提供RGBA缓冲区和位图宽度像

You can simply create an instance of this custom BitmapSource by providing the RGBA buffer and the bitmap width like

var buffer = new byte[] { 25, 166, 0, 255, 90, 0, 120, 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; }
    }
}



正如评论指出的那样,你可能会提高通过实施一个不安全的复制操作,性能这可能是这样的:

As pointed out in a comment, you might improve performance by implementing an unsafe copy operation, which could look like this:

unsafe public override void CopyPixels(
    Int32Rect sourceRect, Array pixels, int stride, 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;
            }
        }
    }
}

这篇关于显示从内存RGBA图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆