3

Я использую следующий фрагмент кода для загрузки изображений в виде эскизов в элемент управления FlowLayoutPanel. К сожалению, я получаю исключение OutOfMemory.Исключение из памяти при загрузке изображений

Как вы уже догадаться, что утечка памяти находится на линии

Pedit.Image = System.Drawing.Image.FromStream(fs) 

Так как я мог оптимизировать следующий код?

Private Sub LoadImagesCommon(ByVal FlowPanel As FlowLayoutPanel, ByVal fi As FileInfo) 
     Pedit = New DevExpress.XtraEditors.PictureEdit 
     Pedit.Width = txtIconsWidth.EditValue 
     Pedit.Height = Pedit.Width/(4/3) 
     Dim fs As System.IO.FileStream 
     fs = New System.IO.FileStream(fi.FullName, IO.FileMode.Open, IO.FileAccess.Read) 
     Pedit.Image = System.Drawing.Image.FromStream(fs) 
     fs.Close() 
     fs.Dispose() 
     Pedit.Properties.SizeMode = DevExpress.XtraEditors.Controls.PictureSizeMode.Zoom 

     If FlowPanel Is flowR Then 
      AddHandler Pedit.MouseClick, AddressOf Pedit_MouseClick 
      AddHandler Pedit.MouseEnter, AddressOf Pedit_MouseEnter 
      AddHandler Pedit.MouseLeave, AddressOf Pedit_MouseLeave 
     End If 

     FlowPanel.Controls.Add(Pedit) 
    End Sub 

Update: Проблема возникает при загрузке количества изображений (3264x2448px в 300dpi - каждое изображение о 3Mb в)

+0

Вы пытались изолировать проблему, удалив все лишнее код и пытается загрузить только изображение? Вы пытались назначить загруженное изображение (если оно так далеко) в «обычный» элемент управления отображением изображения? –

+1

У вас заканчивается память при загрузке только одного изображения или после многих изображений? Это только один конкретный образ, который дает вам проблемы, или он не работает при попытке загрузить любое изображение? Изображения исключительно большие? Пожалуйста, более подробно или лучшее, что мы можем сделать, это догадываться. –

+0

@Jim.Привет, не могли бы вы проверить обновление? – OrElse

ответ

3

Вы можете решить эту проблему в несколько этапов:

  • , чтобы освободиться от файла-зависимости, вы должны скопировать изображения. По-настоящему рисуя его в новом растровом изображении, вы не можете просто скопировать его.
  • , так как вы хотите, чтобы миниатюры, а ваши исходные растровые изображения довольно большие, объедините это с уменьшением изображений.
+0

... и я был готов для публикации третьего связанного вопроса ... Как это управляет программой типа ACDSee? – OrElse

+0

@chocol: Я думаю, ACDsee и тому подобное создают эскизы и используют нагрузку по требованию для остальных. –

5

Документация для Image.FromFile (который связан с вашим FromStream) говорит, что он будет throw OutOfMemoryException, если файл не является допустимым форматом изображения или если GDI + не поддерживает формат пикселей. Возможно, вы пытаетесь загрузить неподдерживаемый тип изображения?

Кроме того, в документации для Image.FromStream указано, что вы должны держать поток открытым на протяжении всего срока службы изображения, поэтому даже если ваш код загрузил изображение, вы, вероятно, получите ошибку, потому что вы закрываете файл, пока изображение все еще активна. См. http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx.

+0

+1 - У меня был текстовый файл, который я загружал – blak3r

3

Пара мыслей:

Во-первых, как и Джим сказал, при использовании Image.FromStream поток должен оставаться открытым в течение всего срока службы изображения, как заметил на странице MSDN. Таким образом, я бы предложил скопировать содержимое файла в MemoryStream и использовать его для создания экземпляра Image. Таким образом, вы можете освободить дескриптор файла как можно скорее.

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

И наконец, не забудьте убрать изображение и поток, когда они больше не нужны.

0

У меня была та же проблема. Ответ Джима Мишеля заставил меня обнаружить загрузку невинного файла .txt. Вот мой метод, если кто-то заинтересован.

Вот мой метод:

/// <summary> 
/// Loads every image from the folder specified as param. 
/// </summary> 
/// <param name="pDirectory">Path to the directory from which you want to load images. 
/// NOTE: this method will throws exceptions if the argument causes 
/// <code>Directory.GetFiles(path)</code> to throw an exception.</param> 
/// <returns>An ImageList, if no files are found, it'll be empty (not null).</returns> 
public static ImageList InitImageListFromDirectory(string pDirectory) 
{ 
    ImageList imageList = new ImageList(); 

    foreach (string f in System.IO.Directory.GetFiles(pDirectory)) 
    { 
     try 
     { 
      Image img = Image.FromFile(f); 
      imageList.Images.Add(img); 
     } 
     catch 
     { 
      // Out of Memory Exceptions are thrown in Image.FromFile if you pass in a non-image file. 
     } 
    } 

    return imageList; 
} 
Смежные вопросы