U4-335 - Image cropper out of memory

Created by Sebastiaan Janssen 19 Aug 2012, 14:51:17 Updated by Sebastiaan Janssen 31 May 2013, 07:46:57

I get this exception if I try to crop an image and press the save button:

Out of memory. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.OutOfMemoryException: Out of memory.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[OutOfMemoryException: Out of memory.] System.Drawing.Bitmap.Clone(Rectangle rect, PixelFormat format) +457510 umbraco.editorControls.imagecropper.ImageTransform.cropImage(Image img, Rectangle cropArea) +152 umbraco.editorControls.imagecropper.ImageTransform.Execute(String sourceFile, String name, Int32 cropX, Int32 cropY, Int32 cropWidth, Int32 cropHeight, Int32 sizeWidth, Int32 sizeHeight, Int64 quality) +666 umbraco.editorControls.imagecropper.ImageInfo.GenerateThumbnails(SaveData saveData, Config config) +639 umbraco.editorControls.imagecropper.DataEditor.Save() +257 umbraco.controls.ContentControl.saveClick(Object Sender, ImageClickEventArgs e) +268 System.Web.UI.WebControls.ImageButton.OnClick(ImageClickEventArgs e) +115 System.Web.UI.WebControls.ImageButton.RaisePostBackEvent(String eventArgument) +120 System.Web.UI.WebControls.ImageButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10 System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13 System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5563

I use the cropper on the Image MediaType to crop an image.

''Originally created on CodePlex by [jbreuer|http://www.codeplex.com/site/users/view/jbreuer]'' on 9/22/2010 6:01:11 PM [Codeplex ID: 28944 - Codeplex Votes: 4]

Imported comments

''Comment by [jbreuer|http://www.codeplex.com/site/users/view/jbreuer] on 9/22/2010 6:04:07 PM:'' Related topic: http://our.umbraco.org/forum/ourumb-dev-forum/bugs/12928-Image-cropper-out-of-memory

''Comment by [Myster|http://www.codeplex.com/site/users/view/Myster] on 8/7/2012 5:12:55 AM:'' Ditto 4.7.1.1, reported from client, the image was only 450x276 I don't have any indication if there was any memory pressure at the time.

I've looked at the src and see there's no using statements wrapping Bitmap. images will not be disposed correctly, and apparently GC is notiorious for failing to collect these types of memory resources in a timely fashion

You must wrap your Graphics, Bitmap, and MemoryStream with using().

see more: http://www.hanselminutes.com/313/deep-inside-image-resizing-and-scaling-with-aspnet-and-iis-with-imageresizingnet-author-na http://nathanaeljones.com/163/20-image-resizing-pitfalls/

''Comment by [sebastiaan|http://www.codeplex.com/site/users/view/sebastiaan] on 8/7/2012 10:31:44 AM:'' @Myster would it be possible to provide the image you were cropping and does it matter to what size you're cropping it?

Comments

Bert Loedeman 23 Nov 2012, 00:13:08

Hi sebastiaan, I get the problem too using v4.10.1. The problem I am facing is very clearly described at http://our.umbraco.org/forum/ourumb-dev-forum/bugs/12928-Image-cropper-out-of-memory?p=1#comment131731... When you know about it, you are able to work around this problem. It is not nice to explain to customers, though ;) ... Cheers, Bert


Sebastiaan Janssen 03 Jan 2013, 16:20:48

Fixed in changeset b15d0ab0b879


Peter Gregory 31 May 2013, 06:39:01

This is still an issue on 4.11.8 (which received the back port of this fix from v6 in v 4.11.7) and 6.x. It will often throw an Out of Memory exception at line 77 of imagemanipulation.cs when the image is very large.

We mainly see the issue cropping larger images, but not always. We have also observed on a number of occasions where the image when scaled down to fit the viewport the rounding of the size values either goes up or down a pixel which when translated to a large picture can put it out by many pixels and then force it to use the default crop setting. I fixed this in my situation by flooring the values that the JS returned.

I have also noticed that it is not very memory efficient. Depending on the number of crops it will load the bitmap 5 times rather than loading it once outside the loop and then reusing the same base bitmap for all crops.

I have also found that the cropping method used is not very efficient either as it loads another image into memory, which is not good in terms of c# objects as they have a max size in memory of 2GB. So if you have a large image (in my case the worst offender was a 5197x3423 at 300dpi jpg) it would balloon out very quickly and sometimes go over this limit. This was the main change to the CropImage method in ImageManipulation.cs from var bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat); return bmpCrop; to Bitmap bmpCrop = new Bitmap(cropArea.Width, cropArea.Height);

using (Graphics g = Graphics.FromImage(bmpCrop)) { g.DrawImage(img, new Rectangle(0, 0, bmpCrop.Width, bmpCrop.Height), cropArea, GraphicsUnit.Pixel); } return bmpCrop;

I have managed to fix all of the above by pulling the cropper out and tweaking it and rewriting it to a new Datatype (needed so we could fix the clients bug). I can provide the code back as a patch. Let me know how best to get this to you.


Sebastiaan Janssen 31 May 2013, 07:46:57

Thanks Peter, added this fix too!


Priority: Normal

Type: Bug

State: Fixed

Assignee:

Difficulty: Normal

Category:

Backwards Compatible: True

Fix Submitted:

Affected versions:

Due in version: 6.0.0

Sprint:

Story Points:

Cycle: