Avatar

I'm really trying to nail out a little more performance out of this tidbit of code. It's not a heavily 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.

Thanks!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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;
}

Refactorings

No refactoring yet !

F9a9ba6663645458aa8630157ed5e71e

Ants

January 9, 2010, January 09, 2010 19:57, permalink

No rating. Login to rate!

What does the profiler say about where the most time is being spent?

Also, have you looked at Image.GetThumbnailImage()?
http://msdn.microsoft.com/en-us/library/system.drawing.image.getthumbnailimage.aspx

Avatar

Kenneth Adams

August 10, 2010, August 10, 2010 19:40, permalink

No rating. Login to rate!

Since you're calling the method 4 times with different target sizes, this refactoring takes one or more target sizes as optional parameters, and returns a List<> that contains the byte[] arrays for each size of JPEG output. This way, you only take the hit of creating the original image in memory once for each set of output images. The original image may be very large (in terms of pixel dimensions), and the Bitmap created from it will take up height*width*4 bytes of memory, even if the original was a JPEG with a relatively small file size.

One other problem with your original code: PixelFormat.Format32bppRgb isn't the "native" format of a .NET Bitmap - the native format is Format32bppArgb. The refactoring below doesn't specify the format anywhere, which lets .NET use the format for which it is optimized.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static List<byte[]> ResizeFile(byte[] orig, params int[] targetSizes)
{
    List<byte[]> ret = new List<byte[]>(targetSizes.Length);
    MemoryStream strmOrig = new MemoryStream(orig);
    Bitmap bmpOrig = (Bitmap)Bitmap.FromStream(strmOrig);
    strmOrig.Close();
    strmOrig.Dispose();
    Size origSize = bmpOrig.Size; 
    foreach (int targetSize in targetSizes)
    {
        Size newSize = CalculateDimensions(origSize, targetSize);
        using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height))
        using (Graphics g = Graphics.FromImage(newImage))
        {
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.DrawImage(bmpOrig, new Rectangle(0, 0, newSize.Width, newSize.Height),
                new Rectangle(0, 0, origSize.Width, origSize.Height),
                GraphicsUnit.Pixel);
            using (MemoryStream m = new MemoryStream())
            {
                newImage.Save(m, ImageFormat.Jpeg);
                ret.Add(m.GetBuffer());
            }
        }
    }
    bmpOrig.Dispose();
    return ret;
}

Your refactoring





Format Copy from initial code

or Cancel