Как я могу написать метод расширения, который преобразует System.Drawing.Bitmap в байтовый массив? - PullRequest
2 голосов
/ 12 января 2011

Как я могу написать метод расширения, который преобразует System.Drawing.Bitmap в байтовый массив?Почему бы и нет:

<Extension()> _
Public Function ToByteArray(ByVal image As System.Drawing.Bitmap) As Byte()
    Using ms = New MemoryStream()
        image.Save(ms, image.RawFormat)
        Return ms.ToArray()
    End Using
End Function

Тем не менее, когда я использую это, я получаю «System.Runtime.InteropServices.ExternalException: универсальная ошибка в GDI +», генерируемую из операции Save ().Что я делаю не так?

Ответы [ 4 ]

4 голосов
/ 12 января 2011

Как заявляет кто-то другой, это известная ошибка GDI +.

Однако обычно она появляется, когда вы закрыли поток source изображения перед тем, как полностью его прочитать.Просто загрузка нового объекта Image будет загружать только метаданные, такие как ширина, высота, глубина цвета и т. Д., А не фактические пиксели.Они будут лениво загружаться позже.

Этого можно избежать, скопировав ваше изображение (во время загрузки) в новое изображение, созданное в памяти.Я предполагаю, что входной поток все еще доступен в то время.Если у вас есть новый класс Image на основе памяти, вы можете свободно распоряжаться исходным потоком.(Другое решение - не закрывать / не удалять исходный поток.) ​​

Редактировать: проблема описана в KB814675 Зависимости растрового изображения и конструктора изображения вместе с обходным решением.

Создание неиндексированного изображения

Этот подход требует, чтобы новое изображение было в неиндексированном пиксельном формате (более 8 бит на пиксель), даже если оригинализображение было в индексированном формате.Этот обходной путь использует метод Graphics.DrawImage () для копирования изображения в новый растровый объект:

  1. Создание исходного растрового изображения из потока, из памяти или из файла.
  2. Создайте новое растровое изображение того же размера с форматом пикселя более 8 бит на пиксель (BPP).
  3. Используйте метод Graphics.FromImage () для получения объекта Graphics для второгоРастровое изображение.
  4. Используйте Graphics.DrawImage () для рисования первого растрового изображения на втором растровом изображении.
  5. Используйте Graphics.Dispose () для удаления графического объекта.
  6. Использование растрового изображения.Dispose () для удаления первого растрового изображения.

Создание индексированного изображения

Этот обходной путь создает объект битовой карты в индексированном формате:

  1. Создайте исходную битовую карту изпоток, из памяти или из файла.
  2. Создайте новое растровое изображение с тем же размером и форматом пикселя, что и у первого растрового изображения.
  3. Используйте метод Bitmap.LockBits () для блокировкиполное изображение для обоих объектов Bitmap в их собственном формате пикселей.
  4. Используйте функцию Marshal.Copy или другую функцию копирования памяти, чтобы скопировать биты изображения из первого Bitmap во второе Bitmap.
  5. Используйте метод Bitmap.UnlockBits (), чтобы разблокировать оба объекта Bitmap.
  6. Используйте Bitmap.Dispose (), чтобы избавиться от первого Bitmap.
1 голос
/ 12 января 2011

Известная ошибка GDI +.

Вы не можете сразу закрыть MemoryStream.

Скопируйте выходной массив в другой байтовый массив, затем закройте поток.

0 голосов
/ 04 декабря 2018

Согласно этой теме, я использовал следующий код, и он работает правильно:

using (var ms = new MemoryStream(bytes))
{
    using (var bitmap = new Bitmap(ms))
    {
        var bitmapCopy = new Bitmap(bitmap, bitmap.Width, bitmap.Height);
        return bitmapCopy;
    }
}
0 голосов
/ 12 января 2011

Попробуйте изменить image.RawFormat на что-то вроде JPEG или PNG. Некоторые изображения могут быть открыты с помощью растрового изображения, но не могут быть сохранены (по крайней мере, в исходном формате).

...