Neil Knight
Neil Knight

Reputation: 48537

Out of memory exception when using WebImage.Resize

I'm using the WebImage in MVC3 in order to resize an image. Basically, the purpose of this is to create a thumbnail image of a file that is uploaded. I will have no control over how large the files are originally, so I need to create a thumbnail of the file in order to speed up the "preview" site.

I have some files which need to be uploaded and in size, its around 4Mb which isn't a problem when it comes to uploading. The problem I'm having is creating the thumbnail. I upload the file first and once its saved on the server, I then create a new WebImage object for the thumbnail.

// Save a thumbnail of the file
WebImage image = new WebImage(savedFileName);

// Resize the image
image.Resize(135, 150, true);

// Save the thumbnail
image.Save(FileName);   // <<--- Out of memory exception here

// Dispose of the image
image = null;

When I try to save the file, I get an Out-of-memory exception. Any ideas on how I can resolve this?

Upvotes: 7

Views: 3852

Answers (5)

Bassem
Bassem

Reputation: 3006

I was getting an OutOfMemoryException from WebImage.Save() when I try to resize and save a JPG image that is using the CMYK color space.

The workaround I found is to save the image to disk and reload it before resizing.

var logoWebImage = new WebImage(newLogo.InputStream);
// Start workaround: Save and reload to avoid OutOfMemoryException when image color space is CMYK.
logoWebImage.Save(filePath: DataFilePaths.LogoImageFile, imageFormat: "png");
logoWebImage = new WebImage(DataFilePaths.LogoImageFile);
// End workaround
logoWebImage.Resize(300, 300, preserveAspectRatio: true, preventEnlarge: true);
logoWebImage.Save(filePath: DataFilePaths.LogoImageFile, imageFormat: "png");

This is an ugly workaround but it is especially needed when the input image is a logo image. Because designers often deliver logo images that use the CMYK color space because it is better for printing.

Upvotes: 3

DenNukem
DenNukem

Reputation: 8254

I ended up doing this as a workaround:

    public static Image ScaleImage(string fileName, int maxWidth, int maxHeight)
    {
        var image = Image.FromFile(fileName);
        var ratioX = (double)maxWidth / image.Width;
        var ratioY = (double)maxHeight / image.Height;
        var ratio = Math.Min(ratioX, ratioY);

        var newWidth = (int)(image.Width * ratio);
        var newHeight = (int)(image.Height * ratio);

        var newImage = new Bitmap(newWidth, newHeight);
        var g = Graphics.FromImage(newImage);
        g.Clear(Color.White); // matters for transparent images
        g.DrawImage(image, 0, 0, newWidth, newHeight);
        return newImage;
    }

Upvotes: 0

Crossems
Crossems

Reputation: 165

I've run into this myself, using WebImage Resize, and found that the issue was a JPG image that was actually a CMYK image. Changing the image mode in PS, to RGB not only reduced the file size that the WebImage Resize method was using, it also performed much faster.

For web usage, I try to ensure all JPG images are RGB and saved in Base Format (as opposed to progressive). This prevents lots of little errors and bugs from occurring.

Upvotes: 4

Neil Knight
Neil Knight

Reputation: 48537

Due to a bug in WebImage, I've had to resort to the code below:

// Save a thumbnail of the file
byte[] fileBytes = System.IO.File.ReadAllBytes(savedFileName);

System.Drawing.Image i;
using (MemoryStream ms = new MemoryStream())
{
    ms.Write(fileBytes, 0, fileBytes.Length);
    i = System.Drawing.Image.FromStream(ms);
}

// Create the thumbnail
System.Drawing.Image thumbnail = i.GetThumbnailImage(135, 150, () => false, IntPtr.Zero);

Upvotes: 8

Aliostad
Aliostad

Reputation: 81660

OK, this looks like a bug in MVC3. The error you are getting is just a standard GDI+ error when GDI+ tries to access pixels in locations where it does not exist.

I believe issue is in the rounding of the pixels when it calculates aspect ratio so I think if you change 135, 150 to for example 136, 151 it will work.

I might have a look later myself to find the bug in their code and post to them.


UPDATE - Possible Workaround

Try passing true for the 4th parameter:

// Resize the image
image.Resize(135, 150, true, true);

I can actually see the bug in code:

    if (num3 > num4)
    {
        height = (int) Math.Round((double) ((num4 * image.Height) / 100.0));
    }
    else if (num3 < num4)
    {
        width = (int) Math.Round((double) ((num3 * image.Width) / 100.0));
    }

Upvotes: 0

Related Questions