Загрузка изображения из потока без сохранения потока открытым
Можно ли использовать метод FromStream System.Drawing.Image без необходимости держать поток открытым в течение всего времени жизни изображения?
У меня есть приложение, которое загружает кучу графики панели инструментов из файлов ресурсов, используя комбинацию Image.FromStream
а также Assembly.GetManifestResourceStream
,
У меня проблема в том, что в Windows 7 это работает нормально, в Windows XP происходит сбой приложения, если элемент пользовательского интерфейса, связанный с одним из этих изображений, отключен. В Windows 7 изображение отображается в оттенках серого. В XP происходит сбой при исключении нехватки памяти.
После большой нагрузки я наконец-то проследил это до начальной загрузки изображения. Разумеется, если я создам какой-либо объект, реализующий IDisposable
это также уничтожается в том же методе, я обертываю его в инструкции использования, например
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
image = Image.FromStream(resourceStream);
}
If I remove the using statement so that the stream isn't disposed, then the application no longer crashes on XP. But I now have a bunch of "orphan" streams hanging about - the images are stored in command classes and these correctly dispose of the images when they themselves are disposed, but the original stream isn't.
Я проверил документацию для FromStream
and it confirms the stream needs to remain open. Why this hasn't crashed and burned on the Windows 7 development system is a mystery however!
I really don't want this stream hanging around, and I certainly don't want to have to store a reference to this stream as well as the image so I can dispose of it later. I only have need of that stream once so I want to get rid of it:)
Is it possible to create the image and then kill of the stream there and then?
4 ответа
Причина, по которой поток должен быть открыт, заключается в следующем:
GDI + и, следовательно, пространство имен System.Drawing могут отложить декодирование битов необработанного изображения до тех пор, пока биты не потребуются изображению. Кроме того, даже после того, как изображение было декодировано, GDI+ может определить, что более эффективно отбрасывать память для большого битового массива и повторно декодировать позже. Следовательно, GDI+ должен иметь доступ к исходным битам для изображения на весь срок действия растрового изображения или объекта Image.
Документированный обходной путь должен создать неиндексированное изображение, используя Graphics.DrawImage
или создать проиндексированный Bitmap
Исходное изображение, как описано здесь:
Зависимости растрового изображения и конструктора изображения
Согласно документации Image.FromStream
поток должен оставаться открытым, пока изображение используется. Следовательно, даже если закрытие сработало (и нечего сказать, что вы не можете закрыть поток до его удаления, поскольку сам объект потока идет), это может быть не очень надежным подходом.
Вы можете скопировать изображение в другой объект изображения и использовать его. Тем не менее, это, вероятно, потребует больше памяти, чем просто держать поток открытым.
Я уверен, что это кому-то поможет:)
Я использовал это для моего dataGridView_SelectionChanged:
private void dataGridViewAnzeige_SelectionChanged(object sender, EventArgs e)
{
var imageAsByteArray = File.ReadAllBytes(path);
pictureBox1.Image = byteArrayToImage(imageAsByteArray);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
Вы можете сохранить поток во временный файл и использовать метод Image.FromFile. Или просто не вставляйте изображение, сохраняйте его в виде файла и загружайте его из этого файла во время выполнения.