2010-12-15

Image Resizing & Cropping on the fly in .NET - high quality

While developing a CMS for small gallery websites, I decided to store only the original uploaded image and not to create a thumbnail upon uploading.
I didn't want, of course, to use the html resizing feature, especially not while uploading high res images.

Instead, I created a generic handler that creates the thumbnail image on the fly.

Not only this handler knows how to resize the image, but also to crop it, in case I want all the images to be on a fixed ratio of width and height.

So, how is it done?
There are many blog posts of resizing images on the fly.
where you'll find a code similar to this:

public static Bitmap CreateThumbnail(Bitmap loBMP, int lnWidth, int lnHeight)
{

System.Drawing.Bitmap bmpOut = null;
try
{
ImageFormat loFormat = loBMP.RawFormat;

decimal lnRatio;
int lnNewWidth = 0;
int lnNewHeight = 0;

//*** If the image is smaller than a thumbnail just return it
if (loBMP.Width <>
return loBMP;


if (loBMP.Width > loBMP.Height)
{
lnRatio = (decimal)lnWidth / loBMP.Width;
lnNewWidth = lnWidth;
decimal lnTemp = loBMP.Height * lnRatio;
lnNewHeight = (int)lnTemp;
}
else
{
lnRatio = (decimal)lnHeight / loBMP.Height;
lnNewHeight = lnHeight;
decimal lnTemp = loBMP.Width * lnRatio;
lnNewWidth = (int)lnTemp;
}

// *** This code creates cleaner (though bigger) thumbnails and properly
// *** and handles GIF files better by generating a white background for
// *** transparent images (as opposed to black)
bmpOut = new Bitmap(lnNewWidth, lnNewHeight);
Graphics g = Graphics.FromImage(bmpOut);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(loBMP, 0, 0, lnNewWidth, lnNewHeight);

loBMP.Dispose();
}
catch
{
return null;
}

return bmpOut;
}

So, this works, and works pretty well.

And as for the cropping?
For that there is no other way but to use twice the
g.DrawImage(bmpTemp, new Rectangle(0, 0, width, height));
once for the size, and another time for the cropping...

And last, but not least, THE QUALITY of the jpeg is determined while outputing the image like here:

context.Response.ContentType = "image/jpeg";
EncoderParameters eps = new EncoderParameters(1);
eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
ImageCodecInfo ici = GetEncoderInfo("image/jpeg");
bmp.Save(context.Response.OutputStream, ici, eps);

so there you have it.
cropping, resizing, and good quality output, on the fly.

now, when doing these actions, the server has to 'work hard' on it for every photo, so a good way will be to cache it REAL GOOD...

context.Response.Cache.SetExpires(DateTime.Now.AddYears(1));
context.Response.CacheControl = "public";
context.Response.Expires = 20160; // two weeks
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetMaxAge(new TimeSpan(1, 0, 0));
context.Response.Cache.SetValidUntilExpires(true);

well, that's it.
enjoy the code...

No comments:

pip install pymssql fails with 'sqlfront.h': No such file or directory

I've tried to install pymssql on Windows using command line: pip install pymssql The operation fails with an error: fatal error C108...