С# Windows 8 Store (Metro, WinRT) Байт-массив для BitmapImage

Я работаю над приложением Windows 8 Metro, которое применяет фильтры к изображениям. У меня есть веб-версия приложения и вы хотите его портировать. Но, как мы все знаем, у WinRT нет всех хороших вещей, которые .NET предоставляет в противном случае:/

В настоящее время я применяю фильтры для байтового массива, и я хочу сохранить его таким образом, потому что он очень быстрый! Поэтому в течение последних нескольких дней я искал способы конвертировать StorageFile в байт [], а затем байт [] в BitmapImage.

До сих пор мне удалось сделать первый (StorageFile to 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;
    }

Это вызывает следующее исключение:

Исключение типа "System.Exception" произошло в mscorlib.dll, но не было обработано в коде пользователя

Дополнительная информация: Компонент не найден. (Исключение из 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;
        }

И получите то же исключение, что и первая часть кода.

Я также пробовал несколько других способов, которые включают использование обычного потока, а затем преобразование в IRandomAccessStream, но они также не работали.

Все приведенные выше коды кажутся мне прекрасными. Поэтому я предполагаю, что проблема заключается в byte[]. Я предполагаю, что формат pixelData внутри недействителен, поэтому я попытался изменить его на RGBA, но это тоже не помогло. Также PixelHeight и PixelWidth BitmapImage равны 0.

Ответы

Ответ 1

Это работает для меня,

    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;
    }

Ответ 2

Это мой первый ответ. Надеюсь, это поможет.

У меня была такая же проблема, и я тренировался более 6 часов, пытаясь разобраться в этом. вот что я придумал: что вы сказали, было правильно. есть 2 способа конвертировать изображение в byteArray:

Первый aproach (ваш)

        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;
    }

если вы используете второй aproach для декодирования картинки без пикселя, этот конвертер будет работать:

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();
    }

для первого aproach вам нужно будет работать с WriteableBitmap, как вы сказали.