Another post for ASP.NET developers reading this blog. If you think these posts do not belong here, please leave a comment, and I'll consider moving my development articles to a separate blog.
Any ASP.NET developer who tries to create "on-the-fly" image-thumbnails in his web-application, sooner or later faces this crappy annoying "out of memory" exception, that is thrown when you use
Image.FromStream
or
Image.GetThumbnailImage
. Sometimes it is thrown when working with big (>5Mb) images, sometimes it's thrown for all images.
Today we faced it in all of our web-based projects - the
help desk system and the
web-based CRM. I spent hours googling for a solution and found nothing. Actually I did found a million suggestions (and even an article claiming that this is a bug in GDI+) - one suggested using
Graphics.DrawImage
instead of
Image.GetThumbnailImage
, another suggested creating a temp file first and then load
Image
from it...
None worked.
Also I found it strange that the error was thrown only under an IIS server, the Visual Studio's built-in development server worked fine...
Anyway. GDI+ (that WinAPI thing that the .NET imaging classes rely on) appears to have some difficulties when working with images in memory, without an actual file. I found a solution, even though it seems more like black magic to me:
Rule 1: When using the Image.FromStream
method keep the stream open for the lifetime of your Image
.
Close the stream only after Disposing the image object. Yes, this might require some refactoring, but you really have no choice.
Image img = Image.FromStream(mystream, true, false);
//... some code
Image thumb = img.GetThumbnailImage(w, h, null, IntPtr.Zero);
//... some code
img.Dispose();
mystream.Close();
This will help you fight the exception when calling
GetThumbnailImage
. In case you
really need to close that stream while continuing working with the image, consider using
Image.Clone()
, but I'm not sure this will help...
Rule 2: Important - set validateImageData
to false
when calling the FromStream
method.
Even after fixing your code with "rule 1" you might still get the exception while calling
FromStream
on large images. This one I actually found on the Microsoft's website -
http://support.microsoft.com/kb/831419... Anyway, here's the code:
//note the third parameter set to "false"!!!
Image img = Image.FromStream(mystream, true, false);