Is There a Reason Image.Fromfile Throws an Outofmemoryexception for an Invalid Image Format

Is there a reason Image.FromFile throws an OutOfMemoryException for an invalid image format?

No, it is history. GDI+ was written quite a while before .NET ever came around. The SDK wrapper for it was written in C++. Exceptions are iffy in C++, not everybody buys into them. Google doesn't for example. So to keep it compatible it reports problems with error codes. That just never scales well, library programmers make it a goal to intentionally limit the number of possible error codes, it lessen the burden on the client programmer having to report them.

GDI+ has this problem in spades, it defines only 20 error codes. That is not much for such a large chunk of code with so many external dependencies. Which in itself is a problem, there are a gazillion ways to mess up an image file. No way that a library's error reporting can be fine-grained enough to cover them all. The fact that these error codes were picked long before .NET defined standard Exception derived types certainly didn't help.

The Status::OutOfMemory error code got overloaded to mean different things. Sometimes it really does mean out of memory, it can't allocate enough space to store the bitmap bits. Sadly, an image file format problem is reported by the same error code. The friction here is that it cannot possibly decide if the width * height * pixels it read from the image file is a problem because there isn't enough storage available for the bitmap. Or if the data in the image file is junk. It assumes that image file is not junk, fair call, that's another program's problem. So OOM is what it reports.

For completeness, these are the error codes:

enum Status
{
Ok = 0,
GenericError = 1,
InvalidParameter = 2,
OutOfMemory = 3,
ObjectBusy = 4,
InsufficientBuffer = 5,
NotImplemented = 6,
Win32Error = 7,
WrongState = 8,
Aborted = 9,
FileNotFound = 10,
ValueOverflow = 11,
AccessDenied = 12,
UnknownImageFormat = 13,
FontFamilyNotFound = 14,
FontStyleNotFound = 15,
NotTrueTypeFont = 16,
UnsupportedGdiplusVersion = 17,
GdiplusNotInitialized = 18,
PropertyNotFound = 19,
PropertyNotSupported = 20,
#if (GDIPVER >= 0x0110)
ProfileNotFound = 21,
#endif //(GDIPVER >= 0x0110)
};

Imagefrom.File(). Out of memory exception

After taking a look at the software you mentioned, as I told you you don't need to load the whole image in memory if you only need a thumbnail.

So I'd create I class

class ImageAndThumb
{
public Image Thumb;
public Image Big;
private string ImagePath;
public ImageAndThumb(string fileName)
{
ImagePath = fileName;
Image image = Image.FromFile(fileName)
Image thumb = img.GetThumbnailImage(200, 200, ()=>false, IntPtr.Zero);
}
public Image LoadBigImage()
{
Big = Image.FromFile(ImagePath);
return Big;
}
public void UnloadImage()
{
Big = null;
}

}

Now we use that class:

List<ImageAndThumb> Images = new List<ImageAndThumb>();
private void LoadBtn_Click_1(object sender, EventArgs e)
{
OpenFileDialog newDialog = new OpenFileDialog();
if (newDialog.ShowDialog() == DialogResult.OK)
{
Images.Clear();

string dirPath = System.IO.Path.GetDirectoryName(newDialog.FileName.ToLower());
DirectoryInfo di = new DirectoryInfo(dirPath);
FileInfo[] finfos = di.GetFiles("*.*");

foreach (FileInfo fi in finfos)
{
string ext = fi.Extension.ToLower();
if ((ext.Equals(".png")) || (ext.Equals(".jpg")) || (ext.Equals(".tif")) || (ext.Equals(".gif")))
{
string Filename = fi.FullName;
ImageAndThumb image = new ImageAndThumb(Filename);
Images.Add(image);
}
}
}

pictureBox3.Image = Images[0].Thumb; // << Much less memory usage;

}

And now whenever you need to use an image load it first
For example:

void ShowPicture(int index)
{
Images[index].LoadBigImage();
PictureBoxBig.image = Images[index].Big;
}
void ClosePicture(int index)
{
Images[index].UnloadImage();
}

one good idea is to unload an image once you load another:

int currentPictureIndex = -1;
void ShowPicture(int index)
{
Images[index].LoadBigImage();
PictureBoxBig.image = Images[index].Big;
if(CurrentPictureIndex > -1) ClosePicture(CurrentPictureIndex);
currentPictureIndex = index;
}

System.Drawing.Image.FromFile System.OutOfMemoryException: Out of memory.

This seemed to fix my issue as it doesn't hold a reference to it this way.

using (var memoryStream = new MemoryStream(File.ReadAllBytes(path)))
{
using (var image = Image.FromStream(memoryStream))
{

byte[] bytes;



using (var memoryStream1 = new MemoryStream())
{
image.Save(memoryStream1, GetImageFormat(Path.GetExtension(path)));
bytes = memoryStream1.ToArray();
}


}
}
}

private ImageFormat GetImageFormat(string extension)
{
switch (extension.ToLower())
{
case ".png":
return ImageFormat.Png;
default:
return ImageFormat.Jpeg;
}
}

Out Of Memory exception on System.Drawing.Image.FromFile()

It's worth knowing that OutOfMemoryException doesn't always really mean it's out of memory - particularly not when dealing with files. I believe it can also happen if you run out of handles for some reason.

Are you disposing of all your bitmaps after you're done with them? Does this happen repeatably for a single image?

How to tackle the Out Of Memory Exception Error?

PictureBox control is used only for showing images in a WinForm application (take a look at MSDN). To show .doc file contents in your application you have to use word or some workaround (like posted here)

C# .Net calling Graphics.FromImage(myBitmap) with certain PixelFormat throws Out of Memory Exception

@pinkfloydx33 has the solution in his comment:

From the docs: This method also throws an exception if the image has any of the following pixel formats... Format16bppArgb1555 Format16bppGrayScale

So they are apparently not supported by GDI+ for some reason.
learn.microsoft.com/en-us/dotnet/api/…

These formats are not supported by GDI+ and there are not enough error codes to handle the reason so it throws "Out of Memory"

Out of memory exception while converting images

Make sure you are building for x64, not x86. If you build for x86, your process will be limited to 2GB of RAM, and the fact that you have 32GB of physical RAM won't matter. You should also Dispose each image by using a using block.

    int height=0,width = 0;
ImageFormat i;
foreach (string pic in files)
{
using (Image temp = Image.FromFile(pic))
{
if (whatisformat() != null)
i = whatisformat();
else
i = GetImageFormat(temp);
if (sizeselected()!=-1)
{
height = sizeselected();
width = getwidth(height);
}
else
{
width = temp.Width;
height = temp.Height;
}
Formatresizesave(temp, i, height, width, destination,Path.GetFileName(pic));
progressBar1.Value++;
}
}
}

Out of Memory with image processing but have lots of RAM

For Legacy reasons, Image.FromFile will throw out of memory exceptions for image files it cannot read.
See Is there a reason Image.FromFile throws an OutOfMemoryException for an invalid image format?

Your png may be invalid and throwing out of memory exceptions for similar reasons



Related Topics



Leave a reply



Submit