Загрузка изображения из потока без сохранения потока открытым - PullRequest
14 голосов
/ 02 октября 2010

Можно ли использовать метод FromStream System.Drawing.Image без необходимости держать поток открытым в течение всего времени жизни изображения?

У меня есть приложение, которое загружает кучу графики панели инструментов из файлов ресурсов, используя комбинацию Image.FromStream и Assembly.GetManifestResourceStream.

Проблема, с которой я столкнулся, заключается в том, что в Windows 7 это работает нормально, в Windows XP происходит сбой приложения, если элемент пользовательского интерфейса, связанный с одним из этих изображений, отключен. В Windows 7 изображение отображается в оттенках серого. В XP происходит сбой при исключении нехватки памяти.

После большой нагрузки я наконец-то проследил ее до начальной загрузки изображения. Разумеется, если я создаю какой-либо объект, реализующий IDisposable, который также уничтожается тем же методом, я обертываю его в операторе using, например

using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
   image = Image.FromStream(resourceStream);
}

Если я удаляю оператор using, чтобы поток не удалялся, тогда приложение больше не падает на XP. Но теперь у меня есть куча «бесхозных» потоков - изображения хранятся в командных классах, и они корректно распределяют изображения, когда они сами располагаются, а исходный поток - нет.

Я проверил документацию для FromStream, и это подтверждает, что поток должен оставаться открытым. Почему это не сработало и не сгорело в системе разработки Windows 7 - загадка!

Я действительно не хочу, чтобы этот поток слонялся поблизости, и я, конечно, не хочу хранить ссылку на этот поток, а также изображение, чтобы я мог утилизировать его позже. Мне нужен этот поток только один раз, поэтому я хочу избавиться от него:)

Можно ли тут же создать образ и затем убить поток?

Ответы [ 4 ]

20 голосов
/ 02 октября 2010

Причиной, по которой поток должен быть открыт, является следующее :

GDI +, и, следовательно, пространство имен System.Drawing может отложить декодированиенеобработанных битов изображения, пока биты не требуются изображением.Кроме того, даже после того, как изображение было декодировано, GDI + может определить, что более эффективно отбрасывать память для большой битовой карты и повторно декодировать позже.Следовательно, GDI + должен иметь доступ к исходным битам для изображения в течение всего жизненного цикла объекта Bitmap или Image .

Документированный обходной путь заключается в создании неиндексированного изображения с использованием Graphics.DrawImage или создании индексированного Bitmap из исходного изображения, как описано здесь:

Зависимости конструктора растрового изображения и изображения

3 голосов
/ 02 октября 2010

В соответствии с документацией Image.FromStream поток должен оставаться открытым во время использования изображения. Поэтому, даже если закрытие сработало (и нечего сказать, что вы не можете закрыть поток до его удаления, поскольку сам объект потока идет), это может быть не очень надежным подходом.

Вы можете скопировать изображение в другой объект изображения и использовать его. Однако это, вероятно, потребует больше памяти, чем просто сохранение потока открытым.

0 голосов
/ 29 марта 2018

Уверен, это кому-нибудь поможет:)

Я использовал его для своих 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;
}
0 голосов
/ 02 октября 2010

Вы можете сохранить поток во временный файл и использовать метод Image.FromFile .Или просто не вставляйте изображение, сохраняйте его в виде файла и загружайте его из этого файла во время выполнения.

...