tags:

views:

125

answers:

3

I'm really trying to nail out a little more performance out of this tidbit of code. It's not a heavly used bit of code but is used every time a new image is uploaded, and 4 times for each image (100px, 200px, 500px, 700px). So when there are any more than 2 or 3 images processing, it gets a little busy on the server. Also I'm trying to figure out how to make it correctly process images with a low resolution. Currently it just chops it off half way through, not plesent. Examples: Original, large, xLarge

public static byte[] ResizeImageFile(byte[] imageFile, int targetSize)
{
    using (System.Drawing.Image oldImage = System.Drawing.Image.FromStream(new MemoryStream(imageFile)))
    {
        Size newSize = CalculateDimensions(oldImage.Size, targetSize);

        using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format32bppRgb))
        {
            newImage.SetResolution(oldImage.HorizontalResolution, oldImage.VerticalResolution);
            using (Graphics canvas = Graphics.FromImage(newImage))
            {
                canvas.SmoothingMode = SmoothingMode.AntiAlias;
                canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
                canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
                canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
                MemoryStream m = new MemoryStream();
                newImage.Save(m, ImageFormat.Jpeg);
                return m.GetBuffer();
            }
        }

    }
}

private static Size CalculateDimensions(Size oldSize, int targetSize)
{
    Size newSize = new Size();
    if (oldSize.Width > oldSize.Height)
    {
        newSize.Width = targetSize;
        newSize.Height = (int)(oldSize.Height * (float)targetSize / (float)oldSize.Width);
    }
    else
    {
        newSize.Width = (int)(oldSize.Width * (float)targetSize / (float)oldSize.Height);
        newSize.Height = targetSize;
    }
    return newSize;
}

Thanks for and help!

+1  A: 

The first thought that comes to mind is, have you thought about Multithreading it? i.e. calling this method for each image (or batch of images) in a separate thread? That way, if your server has a few cores you can get things done quicker. Just a thought...

BFree
Jay Zeng
@Jay Zeng, currently the app is processing the images prior to inserting them into a database. A little caching might go a long way, but I'll have to do a lot more testing to make sure it's not going to affect to much and limit my 6gb of memory even further.
Tim Meers
I like the idea of threading. I should be able to pop it into a new thread, this should speed up the overall view of the site when one user is uploading a lot of files and others are trying to view the rest of the site. I'll get cracking on this tonight! Now any idea on how to make it work better for lower resolution images?
Tim Meers
I've added an example as well of the second issue.
Tim Meers
A: 

Thread

SUMMARY:

If you're batch processing a lot of images, make sure you use at least one more processing thread than you have CPU cores - that way the CPU won't be idle while you're loading and saving files. Also wrap a critical section round the disk I/O calls to avoid thrashing the drive heads by loading / saving two files at once.

For processing a single image at a time, if you have a multi core system the obvious optimization is splitting the image into several smaller ones (or just specifying appropriate source rectangles), and resizing each of those on a separate core.

If you still need more performance then you'll almost certainly need to use native code so you can make use of SSE and other low level optimizations.

adatapost
+1  A: 

(Threading is a great tip.)

Try to call your method with the smallest possible image as input each time, instead of the original image. If the original image is, say 2000px, then create the 700px image from it and then use your newly created 700px image to create the 500px, etc...

With the HighQualityBicubic setting I doubt that you'll notice any difference in the 100px image. (But it of course it needs to be verified.)

danbystrom
I love this idea! I never really thought about in that way either, to me it's like doing it backwards. I normally don't think backwards (despite what my coworkers think). This combined with threading should be a huge help as then it wont have to reprocess the 2 to 4mb file for each image size. I'll test and post the results.
Tim Meers