Исключение нехватки памяти в System.Drawing.Image.FromFile()

У меня есть загрузчик изображений и обрезка, которые создают миниатюры, и я иногда получаю исключение «Недостаточно памяти» в следующей строке:

Dim bm As Bitmap = System.Drawing.Image.FromFile(imageFile)

Возникновение ошибки незначительно и очень редко, но мне всегда хотелось бы знать, что может быть ее причиной. Переменная imageFile — это просто Server.MapPath пути к изображению.

Мне было любопытно, сталкивался ли кто-нибудь с этой проблемой ранее и есть ли у них какие-либо идеи, что может быть ее причиной? Возможно, это размер изображения?

Я могу опубликовать код, если это необходимо, и любую вспомогательную информацию, которая у меня есть, но хотелось бы услышать мнение людей по этому поводу.


person dooburt    schedule 10.07.2009    source источник
comment
Является ли изображение, которое вы пытаетесь загрузить, исключительно большим?   -  person RCIX    schedule 10.07.2009
comment
Все изображения меньше ~700kb.   -  person dooburt    schedule 10.07.2009
comment
Вы уверены, что рассматриваемый файл является допустимым файлом изображения? Я также столкнулся с точно такой же ситуацией, но файл не смог загрузиться ни в какой другой программе.   -  person Dan Byström    schedule 10.07.2009
comment
Примечание: с действительным файлом изображения я ссылался не на тип файла, а на его содержимое. То есть: могут ли данные изображения быть повреждены?   -  person Dan Byström    schedule 10.07.2009
comment
I danby, спасибо за ответ. Это не мое изображение, поэтому я его пришлю и проверю. Человек, который загружает, особенно некомпетентен, поэтому я надеюсь, что это именно так!   -  person dooburt    schedule 10.07.2009
comment
Хорошо, изображение было повреждено. Проблема решена. Спасибо, парни. Дэнби, если ты добавишь свой ответ, я отмечу его как правильный;)   -  person dooburt    schedule 10.07.2009
comment
Была аналогичная проблема. Замечено, что System.Drawing.Image.FromFile вызывает исключение OutOfMemoryException при попытке чтения поврежденных файлов. Это можно воспроизвести, если вы создадите файл изображения размером 0 байт, а затем попытаетесь прочитать его из файла, как вы это сделали.   -  person Sola Oderinde    schedule 21.01.2015


Ответы (13)


Стоит знать, что OutOfMemoryException не всегда действительно означает нехватку памяти, особенно при работе с файлами. Я считаю, что это также может произойти, если у вас по какой-то причине закончились ручки.

Вы избавляетесь от всех своих растровых изображений после того, как с ними покончено? Это повторяется для одного изображения?

person Jon Skeet    schedule 10.07.2009
comment
Привет Джон, спасибо за быстрый ответ. Да, я распоряжаюсь и изображением, и графикой. Dim bmPhoto As New Bitmap(targetW, targetH, PixelFormat.Format24bppRgb) Dim grPhoto As Graphics = Graphics.FromImage(bmPhoto) bmPhoto.Dispose() bmPhoto = Ничего grPhoto.Dispose() grPhoto = Ничего Что касается повторяемости, то нет, она чрезвычайно случайно, но изображения всегда имеют тенденцию быть больше (хотя и не больше 700 тыс.~). - person dooburt; 10.07.2009
comment
Я подозреваю, что это может быть не размер файла, а размер изображения в памяти - очень сильно сжатое изображение с огромным количеством пикселей может вызвать у вас проблемы... - person Jon Skeet; 10.07.2009
comment
Привет Джон, спасибо за комментарий. Оказывается, это поврежденное изображение все время. вздыхает. Некомпетентный пользователь. Хотя спасибо за ответы :) - person dooburt; 10.07.2009
comment
Как вы определили, что изображение было повреждено? У меня также возникают эти ошибки OutOfMemoryException при выполнении Image.FromFile. Что характерно, он выдает исключение только на одном сервере, а не на другом. Могу ли я пропустить какой-то важный кодировщик? Это 4256x2832 24bpp sRGB JPEG, загруженный с изображений Getty. - person Mark Richman; 21.06.2010
comment
Эй, Марк, я просто попытался открыть образ напрямую через ОС. Он не мог открыть его. Ни Photoshop, ни любое другое программное обеспечение для работы с изображениями. Это стало причиной броска. - person dooburt; 16.09.2014

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

using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
   using (Image original = Image.FromStream(fs))
   {
      ...

Использование явного Dispose(), оператора using() или установка значения null в растровом изображении не решает проблему с Image.FromFile.

Поэтому, если ваше приложение работает какое-то время и открывает много файлов, рассмотрите возможность использования вместо него Image.FromStream().

person Ian Mercer    schedule 07.02.2010
comment
На самом деле, если вы удаляете поток, который привязан к файлу через неуправляемый дескриптор, дескриптор будет закрыт тут же, не дожидаясь выполнения сборки мусора. В конце концов, в этом весь смысл IDisposable. - person Lasse V. Karlsen; 29.03.2011
comment
Это тоже можно сделать еще дальше. blogs.msdn.com/b/omars/archive/ 2004/03/29/100941.aspx, по-прежнему применим. - person ; 30.03.2011
comment
как насчет pdf с альфой в этом случае? - person Berker Yüceer; 12.06.2012
comment
Почему вызов Dispose() не освобождает дескриптор файла для изображения? Это просто ошибка в реализации? Почему Microsoft никогда не исправляла эту ошибку? Очевидно, что использование потока лучше по многим причинам, но кажется, что Microsoft должна была решить эту проблему или вообще удалить этот метод. - person crush; 15.12.2015

Сегодня я столкнулся с той же проблемой при создании миниатюр для папки, полной изображений. Получается, что "недостаточно памяти" каждый раз происходило точно в одно и то же время. Когда я посмотрел на папку с изображениями, которые нужно преобразовать, я обнаружил, что файл, который создавал проблему, был thumbs.db. Я добавил некоторый код, чтобы убедиться, что конвертируются только файлы изображений, и проблема была решена.

Мой код в основном

For Each imageFile as FileInfo in fileList
If imageFile.Extension = ".jpg" Or imageFile.Extension = ".gif" Then
    ...proceed with the conversion
End If
Next

Надеюсь это поможет.

person Gilbert Biro Simon    schedule 18.08.2011
comment
Да, необработанный тип изображения выбрасывается как OOM. Получает меня каждый раз. - person Nick Westgate; 18.09.2018

Также вы можете открыть его в режиме чтения (если вы хотите использовать его в двух местах одновременно)

 public Image OpenImage(string previewFile)
        {
            FileStream fs = new FileStream(previewFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            return Image.FromStream(fs);
        }
person Avram    schedule 31.08.2010

Также проверьте, не открывали ли вы этот же файл в другом месте. По-видимому, когда вы дважды открываете файл (даже с помощью File.Open()), также выбрасывается OutOfMemoryException...

person pinus.acer    schedule 23.10.2014

Это происходит, когда файл изображения поврежден. Это плохое сообщение об ошибке, потому что память не имеет к этому никакого отношения. Я не разобрался с кодом, но попытка/поймать/наконец остановит выполнение программы.

person David Grund    schedule 19.05.2019

У меня была аналогичная проблема сегодня, когда я пытался изменить размер изображения, а затем обрезать его, что произошло, так это то, что я использовал этот код для изменения размера изображения.

private static Image resizeImage(Image imgToResize, Size size)
{
   int sourceWidth = imgToResize.Width;
   int sourceHeight = imgToResize.Height;

   float nPercent = 0;
   float nPercentW = 0;
   float nPercentH = 0;

   nPercentW = ((float)size.Width / (float)sourceWidth);
   nPercentH = ((float)size.Height / (float)sourceHeight);

   if (nPercentH < nPercentW)
      nPercent = nPercentH;
   else
      nPercent = nPercentW;

   int destWidth = (int)(sourceWidth * nPercent);
   int destHeight = (int)(sourceHeight * nPercent);

   Bitmap b = new Bitmap(destWidth, destHeight);
   Graphics g = Graphics.FromImage((Image)b);
   g.InterpolationMode = InterpolationMode.HighQualityBicubic;

   g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
   g.Dispose();

   return (Image)b;
}

А потом этот код для урожая...

private static Image cropImage(Image img, Rectangle cropArea)
{
   Bitmap bmpImage = new Bitmap(img);
   Bitmap bmpCrop = bmpImage.Clone(cropArea,
   bmpImage.PixelFormat);
   return (Image)(bmpCrop);
}

Тогда вот как я назвал приведенный выше код...

Image img = Image.FromFile(@"C:\Users\****\Pictures\image.jpg");
img = ImageHandler.ResizeImage(img, new Size(400, 300));
img = ImageHandler.CropImage(img, new Rectangle(0, 25, 400, 250));
long quality = 90;

Я продолжал получать ошибки в части обрезки, изменение размера работало нормально!

Оказывается, то, что происходило внутри ресайзера, вызывало ошибки в функции кадрирования. Расчеты с измененным размером привели к тому, что фактические размеры изображения оказались равными 399, а не 400, которые я передал.

Итак, когда я передал 400 в качестве аргумента для обрезки, он пытался обрезать изображение шириной 399 пикселей с шириной bmp 400 пикселей и выдавал ошибку нехватки памяти!

Большая часть приведенного выше кода была найдена на http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-saving-cropping-and-resizing

person jcreamer898    schedule 29.03.2011

Если изображение является значком, требуется другая обработка загрузки, как в следующей функции:

public static Image loadImage(string imagePath)
    {
        Image loadedImage = null;
        if (!File.Exists(imagePath)) return loadedImage;
        try
        {
            FileInfo fileInfo = new FileInfo(imagePath);
            if (fileInfo.Extension.Equals(".jpg") || fileInfo.Extension.Equals(".jpeg") ||
               fileInfo.Extension.Equals(".bmp") || fileInfo.Extension.Equals(".png") ||
               fileInfo.Extension.Equals(".gif"))
            {
                loadedImage = Image.FromFile(imagePath);
            }
            else if (fileInfo.Extension.Equals(".ico"))
            {
                Bitmap aBitmap = Bitmap.FromHicon(new
                                           Icon(imagePath, new Size(200, 200)).Handle);
                loadedImage = ImageFuncs.ResizeImage(aBitmap, new Size(30, 30));
            }
        }
        catch (Exception eLocal)
        {
            MessageBox.Show(imagePath + " loading error: " + eLocal.Message);
        }
        return loadedImage;
    }
person IrinaL    schedule 24.03.2014

У меня была такая же проблема с утилитой, которую я написал для преобразования TIFF(s) в PDF(s). Часто я получал ошибку «недостаточно памяти» в той же строке, что и вы.

System.Drawing.Image.FromFile(imageFile)

Затем я обнаружил, что ошибка возникает только тогда, когда расширение файла «.tiff», и работает нормально после того, как я переименовал его с расширением «.tif».

person Jeff Chapin    schedule 24.06.2014

У меня была такая же проблема, прежде чем искать другое место в коде, я хотел убедиться, могу ли я открыть изображение с помощью любого средства просмотра изображений, и выяснил, что изображение повреждено/повреждено, хотя это файл .PNG с размером 1 КБ. Добавил новое изображение в том же месте, после чего все заработало.

person Kiran Modini    schedule 27.12.2017

У меня такая же проблема с пакетной обработкой файлов Tiff. Большинство файлов не выдают исключение, но несколько файлов выдают исключение «Недостаточно памяти» в ASP.NET 4.0. Я использовал двоичные данные, чтобы выяснить, почему только для нескольких файлов и из той же папки. Это не может быть проблемой разрешения для учетной записи ASP.NET ASPNET или NETWORK SERVICE, поскольку другие файлы являются рабочими файлами.

Я открыл класс iTextSharp.text.Image и обнаружил множество перегруженных методов для GetInstance(). Я решил свою проблему, используя следующий код: примечание: блок catch будет запускаться для проблемных файлов.

                iTextSharp.text.Image image = null;
            try
                {
                    var imgStream = GetImageStream(path);
                     image = iTextSharp.text.Image.GetInstance(imgStream);
                }
                catch {
                    iTextSharp.text.pdf.RandomAccessFileOrArray ra = null;
                    ra = new iTextSharp.text.pdf.RandomAccessFileOrArray(path);
                    image = iTextSharp.text.pdf.codec.TiffImage.GetTiffImage(ra, 1);

                    if (ra != null)
                        ra.Close();

                }
person Nilesh Hirpara    schedule 31.10.2013
comment
Где в этом случае метод GetImageStream(path)? Если у вас есть объект изображения iTextSharp.text.Image, как вы преобразуете его в объект System.Drawing.Image? - person Chirag; 23.04.2015

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

person Rich    schedule 20.05.2019
comment
Я сделал это после того, как попробовал множество вещей - удаление метаданных из изображения, переименование файла перед загрузкой, загрузку в другую часть системы, загрузку простого (и меньшего изображения) - все безуспешно, попробовал вышеупомянутую переработку перед успешной загрузкой оригинальное изображение. - person Rich; 20.05.2019

Я создал пример минимальной формы, который все еще дает мне ошибки.

        private void button1_Click(object sender, EventArgs e)
    {
        string SourceFolder = ImageFolderTextBox.Text;
        string FileName = "";
        DirectoryInfo Mydir = new DirectoryInfo(SourceFolder);
        FileInfo[] JPEGS = Mydir.GetFiles("*.jpg");
        for (int counter = 0; counter < JPEGS.Count(); counter++)
        {
            FileName = Mydir + "\\" + JPEGS[counter].Name;
            //using (Image MyImage = System.Drawing.Image.FromFile(FileName))
            using (FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                StatusBtn.BackColor = Color.Green;
            }
        }
    }

Я попробовал как закомментированную строку, используя Image.FromFile(), так и строку, используя FileStream(). Оба выдавали файловые ошибки.

Ошибка Image.FromFile(): System.OutOfMemoryException: «Недостаточно памяти»

Ошибка filestream(): System.UnaurthorizedAccessException: «Отказано в доступе к пути «E:\DCIM\100Canon\dsc_7218.jpg».

Я поставил точку останова непосредственно перед строками, вызывающими ошибку, и я могу открыть файл изображения с помощью средства просмотра изображений Windows. Затем я закрыл средство просмотра, и после того, как я перешел к следующей строке и получил сообщение об ошибке, я больше не могу просматривать изображение с помощью средства просмотра Windows. Вместо этого я получаю сообщение о том, что у меня нет разрешения на доступ к файлу. Я могу удалить файл .

Эта ошибка повторяется. Я делал это более 10 раз. Каждый раз, когда я получаю сообщение об ошибке, я удаляю файл, используемый для FileName.

Все файлы были проверены на отсутствие повреждений.

Мой исходный код, который использовал Image.FromFile(), работал нормально, когда я скомпилировал его 2 года назад. На самом деле файл .exe работает нормально. Я сделал незначительное изменение где-то еще в коде и с удивлением обнаружил, что код не компилируется без этой ошибки. Я попробовал метод FileStream() на основе информации на этой странице.

person Adrian Hood Sr    schedule 19.07.2021