Исключение нехватки памяти в System.Drawing.Image.FromFile()
У меня есть загрузчик изображений и кроппер, который создает миниатюры, и я иногда получаю исключение Out Of Memory в следующей строке:
Dim bm As Bitmap = System.Drawing.Image.FromFile(imageFile)
Причина ошибки крошечная и очень редкая, но я всегда хотел бы знать, что может быть причиной ее возникновения. Переменная imageFile - это просто Server.MapPath для пути к изображению.
Мне было любопытно, сталкивался ли кто-нибудь с этой проблемой ранее, и если у них были какие-либо идеи, что могло вызвать это? Возможно, это размер изображения?
При необходимости я могу опубликовать код и любую имеющуюся у меня информацию, но хотел бы услышать мнение людей по этому поводу.
13 ответов
Стоит знать, что OutOfMemoryException не всегда означает, что ему не хватает памяти - особенно не при работе с файлами. Я верю, что это также может произойти, если у вас по какой-то причине закончились ручки.
Вы избавляетесь от всех своих растровых изображений после того, как закончите с ними? Это повторяется для одного изображения?
Если это не был плохой файл изображения, но на самом деле это была обычная проблема с 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()
вместо.
Сегодня я столкнулся с той же проблемой, создавая миниатюрные изображения для папки, полной изображений. Оказывается, "Недостаточно памяти" возникало точно в одной и той же точке каждый раз. Когда я посмотрел на папку с изображениями, которые нужно преобразовать, то обнаружил, что файл, который создавал проблему, был 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
Надеюсь это поможет.
Также проверьте, не открывали ли вы тот же файл где-то еще. По-видимому, когда вы открываете файл дважды (даже с File.Open()), OutOfMemoryException также генерируется...
Также вы можете открыть его в режиме чтения (если вы хотите использовать его в двух местах одновременно)
public Image OpenImage(string previewFile)
{
FileStream fs = new FileStream(previewFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return Image.FromStream(fs);
}
Это происходит, когда файл изображения поврежден. Это плохое сообщение об ошибке, потому что память не имеет к этому никакого отношения. Я не разработал кодирование, но попытка / отлов / наконец остановит завершение программы.
Если изображение является значком, то требуется другая обработка загрузки, как в следующей функции:
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;
}
У меня была такая же проблема с утилитой, которую я написал для преобразования TIFF(s) в PDF(s). Часто я получаю сообщение об ошибке "недостаточно памяти" в той же строке, что и вы.
System.Drawing.Image.FromFile(imageFile)
Затем я обнаружил, что ошибка произошла только тогда, когда расширение файла было ".tiff" и работало нормально после того, как я переименовал его с расширением ".tif"
У меня была похожая проблема сегодня, когда я пытался изменить размер изображения, а затем обрезать его, в результате я использовал этот код для изменения размера изображения.
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 в качестве аргумента для кадрирования, он пытался обрезать изображение шириной 399px с шириной bmp 400px, и это вывело ошибку нехватки памяти!
Большая часть приведенного выше кода была найдена на http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-saving-cropping-and-resizing
У меня была такая же проблема, прежде чем искать другое место в коде, чтобы убедиться, что я могу открыть Изображение с помощью любого средства просмотра изображений и выяснило, что Изображение повреждено / повреждено, хотя это файл.PNG размером 1 КБ. Добавил новое изображение в том же месте, затем он работал нормально.
Если вы работаете с IIS, попробуйте переработать пул приложений. Это решило ошибку загрузки аналогичного изображения "Out of Memory" для меня.
У меня та же проблема пакетной обработки файлов Tiff. Большинство файлов не выдают исключение, но немногие файлы выдают исключение "Недостаточно памяти" в ASP.NET 4.0. Я использовал двоичные данные, чтобы узнать, почему только для нескольких файлов и из той же папки. Это не может быть проблема разрешения для ASP.NET ASPNET или учетной записи NETWORK SERVICE, потому что другие файлы являются рабочим файлом.
Я открыл класс iTextSharp.text.Image и обнаружил, что есть много перегруженных методов для GetInstance(). Я решил свою проблему, используя следующий код: note: 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();
}
Я создал пример минимальной формы, который все еще дает мне ошибки.
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() на основе информации на этой странице.