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

могу написать метод расширения, который преобразует 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 (). Что я делаю неправильно?

 Adam Houldsworth12 янв. 2011 г., 17:53
@Mathias, по крайней мере, в C # независимо от того, где вы возвращаетесь внутри использования, метод dispose срабатывает. Не могу говорить за VB.NET, но я предполагаю, что это то же самое.
 MusiGenesis12 янв. 2011 г., 17:53
@Mathias:using блоки в .Net по-прежнему работают, как и ожидалось, даже когда выreturn от них, так что это не проблема этого парня.
 Mathias Lykkegaard Lorenzen12 янв. 2011 г., 17:50
Я не думаю, что строка «конец использования» когда-либо запускается из-за оператора return, поэтому что-то не очищается должным образом. Кроме того, попробуйте поэкспериментировать с закрытием потока перед преобразованием его в массив.

Ответы на вопрос(4)

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

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

 Patrick Szalapski12 янв. 2011 г., 18:31
Не сработало При отладке я вижу, что исключение выдается из вызова Save (Stream, ImageFormat), а не после.
 leppie12 янв. 2011 г., 18:45
Какой тип изображения? Как это было создано? Что такое пиксельный формат?
 Patrick Szalapski12 янв. 2011 г., 18:58
JPEG в 24bppRGB. Он был создан из байтового массива, преобразованного в поток и переданного в конструктор Bitmap (Stream).
 sisve12 янв. 2011 г., 20:03
@ Патрик: Смотри мой ответ. Вы уже закрыли этот исходный поток, что делает ваш объект Image неспособным загружать пиксели.
Решение Вопроса

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

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

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

Создать неиндексированное изображение

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

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

Создать индексированное изображение

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

Создайте исходное растровое изображение из потока, из памяти или из файла.Создайте новое растровое изображение с тем же размером и форматом пикселя, что и у первого растрового изображения.Используйте метод Bitmap.LockBits (), чтобы заблокировать все изображение для обоих растровых объектов в их собственном формате пикселей.Используйте функцию Marshal.Copy или другую функцию копирования из памяти, чтобы скопировать биты изображения из первого битового массива во второй битовый массив.Используйте метод Bitmap.UnlockBits (), чтобы разблокировать оба объекта Bitmap.Используйте Bitmap.Dispose (), чтобы избавиться от первого Bitmap.
 Patrick Szalapski12 янв. 2011 г., 22:21
Это кажется проблемой. Любые предложения о том, как скопировать растровое изображение в растровое изображение? Кажется, что конструктор растрового изображения New (Image) фактически меняет растровое изображение на другой формат. Или есть другой способ заставить Bitmap загружаться?
 sisve12 янв. 2011 г., 22:27
Возьмите ваш исходный поток, скопируйте его в MemoryStream, загрузите с него иDonT распоряжаться MemoryStream. Созданный класс Image будет по-прежнему сохранять ссылку на него, и он будет удален, когда ваше изображение будет.
 Patrick Szalapski12 янв. 2011 г., 22:40
Но это нарушает правило CA2000, и поэтому я не могу развернуть. Есть другие идеи? (msdn.microsoft.com/en-us/library/ms182289.aspx)
 sisve13 янв. 2011 г., 06:40
Я отредактировал ответ, включив в него информацию из KB814675, которая описывает вашу проблему и возможное решение.
 Patrick Szalapski13 янв. 2011 г., 14:57
Итак, похоже, что ЛИБО вы оставляете поток памяти открытым до тех пор, пока система не соберет мусор, ИЛИ не выполните один из приведенных выше танцев копирования / перерисовки - фактически прочитав каждый байт изображения дважды. Похоже, System.Drawing.Bitmap может использовать некоторые улучшения, чтобы обеспечить более надежный способ сделать это. Спасибо за настойчивость здесь.

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

using (var ms = new MemoryStream(bytes))
{
    using (var bitmap = new Bitmap(ms))
    {
        var bitmapCopy = new Bitmap(bitmap, bitmap.Width, bitmap.Height);
        return bitmapCopy;
    }
}

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

 Patrick Szalapski12 янв. 2011 г., 18:14
Попробовал явно указать JPEG (так как это мой тестовый растр); без изменений.

Ваш ответ на вопрос