3

Hi I am trying to upload some images async, I get Out of Memory Exception, I am disposing by using statement however I get following stack trace

[OutOfMemoryException: Out of memory.]
   System.Drawing.Graphics.CheckErrorStatus(Int32 status) +1146420
   System.Drawing.Graphics.DrawImage(Image image, Rectangle destRect, Int32 srcX, Int32 srcY, Int32 srcWidth, Int32 srcHeight, GraphicsUnit srcUnit, ImageAttributes imageAttrs, DrawImageAbort callback, IntPtr callbackData) +256
   System.Drawing.Graphics.DrawImage(Image image, Rectangle destRect, Int32 srcX, Int32 srcY, Int32 srcWidth, Int32 srcHeight, GraphicsUnit srcUnit, ImageAttributes imageAttr) +48

Here is resizer, where I get exception:

public Bitmap ResizeImage(Image image, int width, int height)
        {
          var newWidth = (int)(imageWidth * ratio) < 210 ? 210 : (int)(imageWidth * ratio);
          var newHeight = (int)(imageHeight * ratio) < 210 ? 210 : (int)(imageHeight * ratio);
            //Image resize logic

            var destRect = new Rectangle(0, 0, newWidth, newHeight);
            var destImage = new Bitmap(newWidth, newHeight);
            destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

            using (var graphics = Graphics.FromImage(destImage))
            {
                graphics.CompositingMode = CompositingMode.SourceCopy;
                graphics.CompositingQuality = CompositingQuality.HighQuality;
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

                using (var wrapMode = new ImageAttributes())
                {
                    wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                    /*Here I get error*/graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel,
                        wrapMode);
                }
            }

            return destImage;
        }

Here which uploads image:

private async Task<short> UploadImage(string title, HttpPostedFileBase file, short dimensionWidth,
            short dimensionHeight)
        {
            var blockBlob = CloudBlobContainer.GetBlockBlobReference(title);
            var jpgInfo = ImageCodecInfo.GetImageEncoders().First(codecInfo => codecInfo.MimeType == "image/jpeg");
            using (var image = Image.FromStream(file.InputStream, true, true))
            {
                using (var stream = new MemoryStream())
                using (var encParams = new EncoderParameters(1))
                {
                    encParams.Param[0] = new EncoderParameter(Encoder.Quality, 60L);
                    if (image.Width > dimensionWidth && image.Height > dimensionHeight)
                        using (Bitmap bitMapImage = ResizeImage(image, dimensionWidth, dimensionHeight))
                        {
                            bitMapImage.Save(stream, jpgInfo, encParams);
                        }
                    else
                    {
                        image.Save(stream, jpgInfo, encParams);
                    }
                    stream.Position = 0;
                    await blockBlob.UploadFromStreamAsync(stream);
                    blockBlob.Properties.CacheControl = "public, max-age=864000";
                    blockBlob.SetProperties();
                }
            }
            return (short)EnumData.EOpStatus.Success;
        }

Here is main function:

        public async Task<string> UploadImages(string title, IEnumerable<HttpPostedFileBase> files, short fileCount)
        {
            var fileIndex = 0;
            var imageCsv = String.Empty;
            var uploadTask = new Task<short>[fileCount * 2];
            foreach (var file in files)
            {
                var fullTitle = title + "-" + Convert.ToString(fileIndex) + Path.GetExtension(file.FileName);
                uploadTask[fileIndex] = UploadImage(fullTitle, file, 1440, 900);
                uploadTask[fileIndex + 1] = UploadImage("thumb-" + fullTitle, file, 280, 280);
                imageCsv += String.IsNullOrEmpty(imageCsv) ? fullTitle : "," + fullTitle;
                /*await Task.WhenAll(uploadTask[fileIndex], uploadTask[fileIndex + 1]);*///Works fine in this case 

                fileIndex += 2;
            }
            await Task.WhenAll(uploadTask);
            return imageCsv;
        }

So after some uploads I get an error

Performance Monitor seems normal through out application use, I think its normal enter image description here

19
  • Have you tried running Visual Studio's Memory Analysis tools? Commented Nov 23, 2015 at 7:07
  • 3
    That might not be an actual OOM error. GDI+ likes returning such an error when you pass it invalid parameters. Commented Nov 23, 2015 at 7:20
  • @Micky nope trying with performance monitor now though Commented Nov 23, 2015 at 7:40
  • That reminds me - there is a limit to GDI objects irrespective to the amount of free RAM you have. stackoverflow.com/questions/9723470/…. Though you seem to be doing a pretty good job managing them Commented Nov 23, 2015 at 7:57
  • 2
    When working with GDI (which Bitmap is just a wrapper for) OutOfMemoryException would be better named OutOfHandlesException or OutOfUnManagedMemoryException , it has often has nothing to do with # bytes allocated by the CLR. It is all unmanaged memory and GDI handles. However, looking at your code I don't see any obvious mistakes that would cause a memory or handle leak. Are you working with very large images? Commented Nov 24, 2015 at 16:15

2 Answers 2

0

I believe you are indeed trying to paint outside the destination rectangle... if you notice your code you are in fact (in the line marked) painting image.Width and image.Height (original dimensions), and not the ratio-applied dimensions...

Sign up to request clarification or add additional context in comments.

4 Comments

I think you are taking of drawImage? we should draw from whole image rather than some fixed with, here please check link msdn.microsoft.com/en-us/library/ms142045(v=vs.110).aspx
out of curiosity, just try graphics.DrawImage(image, destRect, 0, 0, 50, 50, GraphicsUnit.Pixel, wrapMode);
but what about fixed size, as i suggested? same exception?
ya tried fixed size i.e. with 200, 50 and normal too
0

Dispose sourceImage and destImage after job is done.

1 Comment

Your answer looks Ok to me, but could you explain a bit more why that works and maybe provide a code snippet how to do this? That would make it much easier for future visitors of this post to get to their solution. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.