C# Windows 8 应用商店(Metro,WinRT)字节数组转换为BitmapImage

15

我正在开发一个Windows 8 Metro应用程序,该应用程序可以对图像应用滤镜。我有一个网络版的应用程序,想要移植到WinRT上。但众所周知,WinRT没有.NET提供的所有好东西 :/

目前,我正在对一个字节数组应用滤镜,并且希望保持这种方式,因为它非常快!因此,在过去的几天里,我一直在寻找将StorageFile转换为byte[],然后再将byte[]转换为BitmapImage的方法。

到目前为止,我已经成功地完成了第一个步骤(从StorageFile到byte[])。以下是我的代码:

public async Task<Byte[]> ImageFileToByteArray(StorageFile file)
    {
        IRandomAccessStream stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
        BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
        PixelDataProvider pixelData = await decoder.GetPixelDataAsync();
        return pixelData.DetachPixelData();
    }

这段代码返回一个包含像素数据的byte[],格式为BGRA。

接下来是棘手的部分。我无法成功地将字节数组转换为BitmapImage。我已经到处搜索过,许多人建议使用WriteableBitmap,但对我没有什么帮助。我还找到了一些应该可以工作的代码片段......但它们并没有起作用。

我尝试过的一个解决方案是像这样使用InMemoryRandomAccessStream:

public async Task<BitmapImage> ByteArrayToBitmapImage(Byte[] pixels)
    {
        var stream = new InMemoryRandomAccessStream();
        await stream.WriteAsync(pixels.AsBuffer());
        stream.Seek(0);
        var image = new BitmapImage();
        await image.SetSourceAsync(stream);
        return image;
    }
这段代码引发了以下异常:

An exception of type 'System.Exception' occurred in mscorlib.dll but was not handled in user code
Additional information: The component cannot be found. (Exception from HRESULT: 0x88982F50)

我尝试使用以下代码替换了它:
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
            BitmapPixelFormat.Bgra8, 
            BitmapAlphaMode.Ignore, 
            new BitmapTransform(),
            ExifOrientationMode.IgnoreExifOrientation, 
            ColorManagementMode.DoNotColorManage);

但这对我没有好处,因为我不断地收到那个异常。

我也尝试了这个:

var bitmapImage = new BitmapImage();
        var pixels = await ImageFileToByteArray(file);
        ImageSource imgSource;
        using (InMemoryRandomAccessStream ms = new InMemoryRandomAccessStream())
        {
            using (DataWriter writer = new DataWriter(ms.GetOutputStreamAt(0)))
            {
                writer.WriteBytes(pixels);
                await writer.StoreAsync();
            }

            await bitmapImage.SetSourceAsync(ms);
            imgSource = bitmapImage;
        }

并获得与第一段代码相同的异常。

我还尝试了几种其他方法,包括使用普通的Stream然后转换为IRandomAccessStream,但它们也没有起作用。

对我来说,上述所有代码都看起来很好。因此,我目前的猜测是问题出在byte[]中。 我猜想像素数据内部的格式无效,因此我尝试将其更改为RGBA,但也没有帮助。另外,BitmapImage的PixelHeight和PixelWidth为0。


你找到解决办法了吗?我也遇到了同样的问题。 - TheQuestioner
2个回答

13

这对我很有效,

    private async Task<BitmapImage> ByteArrayToBitmapImage(byte[] byteArray)
    {
        var bitmapImage = new BitmapImage();

        var stream = new InMemoryRandomAccessStream();
        await stream.WriteAsync(byteArray.AsBuffer());
        stream.Seek(0);

        bitmapImage.SetSource(stream);
        return bitmapImage;
    }

不得不寻找到零点 (stream.Seek(0)) 才能正常工作 :) 非常感谢 :) - Bassem Wissa

1
这是我的第一个答案..希望它能帮助到您。
我遇到了完全相同的问题,花费了6个多小时来解决它。这是我想出的方法:
你说得没错。有两种方法将图像转换为字节数组:
第一种方法(你的方法)
        public async Task<byte[]> ImageFileToByteArrayAsync(StorageFile file)
    {
        IRandomAccessStream stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
        BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
        PixelDataProvider pixelData = await decoder.GetPixelDataAsync();
        return pixelData.DetachPixelData();
    }

第二种方法。
        public async Task<byte[]> ImageFileToByteArrayAsync(StorageFile file)
    {
        var inputStream = await file.OpenSequentialReadAsync();
        var readStream = inputStream.AsStreamForRead();
        var buffer = new byte[readStream.Length];
        await readStream.ReadAsync(buffer, 0, buffer.Length);
        return buffer;
    }

如果您使用第二种方法来解码图片,没有Pixel,那么这个转换器将起作用:
public class ByteArrayToImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value == null || !(value is byte[]))
            return null;

        using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
        {
            using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
            {
                writer.WriteBytes((byte[])value);
                writer.StoreAsync().GetResults();
            }
            BitmapImage image = new BitmapImage();
            image.SetSource(stream);
            return image;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, string language)                                                                         
    {
        throw new NotImplementedException();
    }

对于第一种方法,你需要像你说的那样使用WriteableBitmap。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接