0

I am totally stuck on image resizing because I am getting OutOfMemoryException using the typical examples of image resizing that can be found on the many questions that feature OOMs.

I even tried DynamicImage, which can be found on Nuget, and this also threw an OutOfMemoryException.

Can anyone tell me how I can reduce the quality/size of an image in C#, without loading it into memory?

Edit: I want the c# equivalent to this, if there is one?

Edit: I give up with the typical methods of resizing, as I just can't avoid OutOfMemoryExceptions on my live site, which is running on an old server.

Further Edit: My server's OS is Microsoft Server 2003 Standard Edition

I can post examples of my code, but I'm trying to find a way around OutOfMemoryExceptions.

public static void ResizeImage(string imagePath, int imageWidth, int imageHeight, bool upscaleImage) {
      using (Image image = Image.FromFile(imagePath, false)) {
        int width = image.Width;
        int height = image.Height;
        if (width > imageWidth || height > imageHeight || upscaleImage) {

          image.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
          image.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);

          float ratio = 0;
          if (width > height) {
            ratio = (float)width / (float)height;
            width = imageWidth;
            height = Convert.ToInt32(Math.Round((float)width / ratio));
          }
          else {
            ratio = (float)height / (float)width;
            height = imageHeight;
            width = Convert.ToInt32(Math.Round((float)height / ratio));
          }

          using (Bitmap bitmap = new Bitmap(width, height)) {
            bitmap.SetResolution(image.HorizontalResolution, image.VerticalResolution);
            using (Graphics graphic = Graphics.FromImage(bitmap)) {

              graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
              graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
              graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
              graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
              graphic.DrawImage(image, 0, 0, width, height);

              string extension = ".jpg"; // Path.GetExtension(originalFilePath);

              using (EncoderParameters encoderParameters = new EncoderParameters(1)) {
                encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
                using (MemoryStream imageMemoryStream = new MemoryStream()) {
                  bitmap.Save(imageMemoryStream, GetImageCodec(extension), encoderParameters);
                  using (Image result = Image.FromStream(imageMemoryStream, true, false)) {
                    string newFullPathName = //path;
                    result.Save(newFullPathName);
                  }
                }
              }
            }
          }
        }
      }
        }

I also tried this code as I hoped GetThumbnailImage would reduce the picture quality/size for me, but this is also throwing an OOM exception:

viewModel.File.SaveAs(path);
        Image image = Image.FromFile(path);
        Image thumbnail = image.GetThumbnailImage(600, 600, null, new IntPtr());
        image.Dispose();
        File.Delete(path);
        thumbnail.Save(path);
        thumbnail.Dispose();

Again, both my code examples work for me in my local machine, so I am not trying to find faults/fixes in the code as they should be fine. I'm looking for any solution to avoid the OOM exceptions, I had the idea of reducing the fize size somehow without loading the image into memory, but any alternative ideas that can help me would be appreciated.

Community
  • 1
  • 1
DevDave
  • 6,700
  • 12
  • 65
  • 99
  • 2
    Please post what you've tried. I may just be an error in your code. – ic3b3rg Jan 20 '13 at 18:12
  • I've explained that I have even tried Nuget packages and the underlying error is still there. I believe the issue is with server that hosts my site as I don't get OutOfMemoryExceptions when running on my own machine. But my question is if I can reduce the size of an image without loading it into memory, and I would like to know if its possible and where to start if so. – DevDave Jan 20 '13 at 18:15
  • [Required, FileExtensionsAttribute("jpg|png|gif|jpeg")] public HttpPostedFileBase File { get; set; } – DevDave Jan 20 '13 at 18:25
  • I higly doubt that problem is in image size, it's most likely you are not disposing objects properly resulting in outofmemory exception. What is the file size of the image that you working with? The best would be if you post your code as @ic3b3rg already suggested. Just to make thinks clear, there is no way you can resize image without loading into memory. – Gregor Primar Jan 20 '13 at 18:34
  • I've tried several examples incase I was missing something, including Nuget code. Every instance I tried (including the my 2 examples and DynamicImage, worked locally but not on the server). Could this still be the case and an exception would be thrown on machine but not the other? Genuine question. – DevDave Jan 20 '13 at 18:37
  • 1
    Yes - it's possible to receive an OOM in prod but not dev due to different server settings. A couple off the top of my head - less physical RAM on the server, x86 vs x64, fragmentation, processModel or IIS limits (not sure if that'd be an OOM or just a restart), etc. – Mark Brackett Jan 21 '13 at 03:26

3 Answers3

1

You can try using ImageMagick via command line or the .NET bindings. ImageMagick has some options to resize as the file is being read, which should reduce memory consumption.

Mark Brackett
  • 84,552
  • 17
  • 108
  • 152
0

It may be that the "image" you are using is either not a supported format or is corrupted.

Richard Schneider
  • 34,944
  • 9
  • 57
  • 73
0

I failed to mention that I inherited legacy code that was not disposing of images properly, because I did not think it was relevant since fixing it. The strange thing is, after restarting the website and the AppPool, I was able to upload pictures again without getting an OutOfMemoryExcepiton. I'm struggling to understand why this happened as I have changed the code to dispose of images properly and have done several deploys since, so I would expect that to clear any undisposed images from memory? All the code for picture resizing and uploading was in a static class and I believe that GC.collect() does not work on static variables?

My theory is that the undisposed images have built up in memory and have remained even when I have redepolyed to the site, as that's the only conclusion I can reach since the code began working again after restarting the app pool.

I would delete my question but it has been answered now, happy to reassign the answer if anyone can help explain what was going on here.

DevDave
  • 6,700
  • 12
  • 65
  • 99