byte[] для преобразования BitmapImage не удается

У меня проблема. Я хочу преобразовать BitmapImage в массив byte[] и обратно.

Я написал эти методы:

public static byte[] ToByteArray(this BitmapImage bitmapImage)
{
    byte[] bytes;
    using (MemoryStream ms = new MemoryStream())
    {
        bitmapImage.BeginInit();
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapImage.StreamSource.CopyTo(ms);
        bitmapImage.EndInit();
        bytes = ms.ToArray();
    }
    return bytes;
}

public static BitmapImage ToBitmapImage(this byte[] bytes, int width, int height)
{
    BitmapImage bitmapImage = new BitmapImage();
    using (MemoryStream ms = new MemoryStream(bytes))
    {
        ms.Position = 0;
        bitmapImage.BeginInit();
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapImage.StreamSource = ms;
        bitmapImage.EndInit(); // HERE'S AN EXCEPTION!!!
    }
    return bitmapImage;
}

Первый работает нормально, но когда я пытаюсь преобразовать из byte[] в BitmapImage, я получаю NotSupportedException... Почему? Как исправить код 2-го способа?


person Nickon    schedule 13.01.2013    source источник
comment
Я только что проверил код, который вы разместили, и он отлично сработал для меня. Вы уверены, что ваши байты являются допустимым изображением?   -  person John Koerner    schedule 13.01.2013
comment
BitmapImage должно быть действительным, потому что я отображаю его в своей форме:/ Не знаю, в чем проблема...   -  person Nickon    schedule 13.01.2013
comment
У меня возникают проблемы с работой метода ToByteArray, я продолжаю получать сообщения об ошибках, указывающих, что «Невозможно установить состояние инициализации более одного раза». в строке BeginInit. Мне интересно, возвращает ли что-то в этом методе недопустимые байты.   -  person John Koerner    schedule 13.01.2013
comment
Перейдите по этой ссылке — social.msdn.microsoft.com/Forums/en-US/winforms/thread/   -  person Rohit Vats    schedule 13.01.2013


Ответы (1)


Есть две проблемы с вашим методом ToByteArray.

Сначала он вызывает BeginInit и EndInit для уже инициализированного экземпляра BitmapImage. Это запрещено, см. список Исключений в BeginInit.

Во-вторых, этот метод нельзя было вызвать для BitmapImage, созданного из Uri вместо Stream. Тогда свойство StreamSource будет null.

Я предлагаю реализовать метод, как показано ниже. Эта реализация будет работать для любого BitmapSource, а не только для BitmapImages. И вы можете управлять форматом изображения, выбрав соответствующий BitmapEncoder, например. JpegBitmapEncoder вместо PngBitmapEncoder.

public static byte[] ToByteArray(this BitmapSource bitmap)
{
    var encoder = new PngBitmapEncoder(); // or any other encoder
    encoder.Frames.Add(BitmapFrame.Create(bitmap));

    using (var ms = new MemoryStream())
    {
        encoder.Save(ms);
        return ms.ToArray();
    }
}

Буфер изображения, возвращаемый этим методом ToByteArray, всегда можно преобразовать обратно в BitmapImage с помощью вашего метода ToBitmapImage.

Обратите внимание, что аргументы ширины и высоты вашего метода ToBitmapImage в настоящее время не используются.


ОБНОВИТЬ

Альтернативная реализация метода декодирования может выглядеть так, как показано ниже, хотя она возвращает не BitmapImage, а только экземпляр базового класса BitmapSource. Однако вы можете изменить тип возвращаемого значения на BitmapFrame.

public static BitmapSource ToBitmapImage(this byte[] bytes)
{
    using (var stream = new MemoryStream(bytes))
    {
        var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
        return decoder.Frames[0];
    }
}
person Clemens    schedule 13.01.2013
comment
Я попробовал ваш метод ToByteArray, но по-прежнему получаю ту же ошибку в моем методе ToBitmapImage. Вы знаете, как преобразовать массив byte[] в BitmapImage другим способом? - person Nickon; 13.01.2013
comment
Ваш метод ToByteArray выглядит нормально. Возможно, вы можете удалить оператор ms.Position = 0;, так как он избыточен. Я отредактировал свой ответ, чтобы предоставить альтернативное решение для декодирования изображения. Однако обратите внимание, что этот метод возвращает не BitmapImage, а BitmapFrame. - person Clemens; 13.01.2013
comment
Думаю, я могу просто преобразовать BitmapSource в BitmapImage? - person Nickon; 13.01.2013
comment
Нет, ты не можешь. Это BitmapFrame, а не BitmapImage. Оба имеют BitmapSource как общий базовый класс, но вы не можете привести один к другому. Зачем именно вам нужен BitmapImage? BitmapSource обычно предоставляет всю необходимую информацию о растровом изображении. - person Clemens; 13.01.2013
comment
Нет, мне не нужно BitmapImage. Мне просто нужно 3 метода. Первый, который преобразует мой System.Windows.Controls.Image в Bitmap/BitmapImage/etc., второй, который преобразует его в массив byte[] (мне нужно сериализовать изображение в двоичный файл), и третий, который преобразует массив byte[] обратно в мое изображение (потому что я хочу отобразить его используя привязку для System.Windows.Controls.Image. - person Nickon; 13.01.2013
comment
Хорошо, тогда вы можете попробовать альтернативный метод. Вы можете напрямую назначить возвращенный BitmapSource свойству Image.Source. - person Clemens; 13.01.2013