This is the example scenario. You have been asked to make a page that enables a user to upload any image they want so that it can be manipulated to ensure it is 200px x 200px and compressed to a smaller file size. I won't talk you though how to make the uploading part as there are a plethora of blogs discussing that already. What I will discuss is how to resize crop and compress that image.
Say you have an image that is 1000px x 800px. There are 3 main steps to converting it to a compressed 200px x 200px image:
Resizing an image
To resize it the key is that it needs to keep the same aspect ratio whilst being a lot smaller.So the expected outcome of this stage will be that the shortest of the two dimensions will be 200px, the other will be larger and the aspect ratio will remain the same. Begin code:
private byte[] GetCroppedImage(byte[] originalBytes, Size size, ImageFormat format) { using (var streamOriginal = new MemoryStream(originalBytes)) using (var imgOriginal = Image.FromStream(streamOriginal)) { //get original width and height of the incoming image var originalWidth = imgOriginal.Width; // 1000 var originalHeight = imgOriginal.Height; // 800 //get the percentage difference in size of the dimension that will change the least var percWidth = ((float)size.Width / (float)originalWidth); // 0.2 var percHeight = ((float)size.Height / (float)originalHeight); // 0.25 var percentage = Math.Max(percHeight, percWidth); // 0.25 //get the ideal width and height for the resize (to the next whole number) var width = (int)Math.Max(originalWidth * percentage, size.Width); // 250 var height = (int)Math.Max(originalHeight * percentage, size.Height); // 200 //actually resize it using (var resizedBmp = new Bitmap(width, height)) { using (var graphics = Graphics.FromImage((Image)resizedBmp)) { graphics.InterpolationMode = InterpolationMode.Default; graphics.DrawImage(imgOriginal, 0, 0, width, height); } } } }
Cropping an image
After the last step you are left with an image that is 250px x 200px. As you will notice that is still an aspect ratio of 5:4 so it does not look squashed. However this still isn't the right size so you will now need to crop it.You are now intending to cut off the excess from both sides to reduce the width whilst leaving the height the same. This will leave you with a 200px x 200px image. Code on:
private byte[] GetCroppedImage(byte[] originalBytes, Size size, ImageFormat format) { using (var streamOriginal = new MemoryStream(originalBytes)) using (var imgOriginal = Image.FromStream(streamOriginal)) { //get original width and height of the incoming image var originalWidth = imgOriginal.Width; // 1000 var originalHeight = imgOriginal.Height; // 800 //get the percentage difference in size of the dimension that will change the least var percWidth = ((float)size.Width / (float)originalWidth); // 0.2 var percHeight = ((float)size.Height / (float)originalHeight); // 0.25 var percentage = Math.Max(percHeight, percWidth); // 0.25 //get the ideal width and height for the resize (to the next whole number) var width = (int)Math.Max(originalWidth * percentage, size.Width); // 250 var height = (int)Math.Max(originalHeight * percentage, size.Height); // 200 //actually resize it using (var resizedBmp = new Bitmap(width, height)) { using (var graphics = Graphics.FromImage((Image)resizedBmp)) { graphics.InterpolationMode = InterpolationMode.Default; graphics.DrawImage(imgOriginal, 0, 0, width, height); } //work out the coordinates of the top left pixel for cropping var x = (width - size.Width) / 2; // 25 var y = (height - size.Height) / 2; // 0 //create the cropping rectangle var rectangle = new Rectangle(x, y, size.Width, size.Height); // 25, 0, 200, 200 //crop using (var croppedBmp = resizedBmp.Clone(rectangle, resizedBmp.PixelFormat)) { } } } }
Compressing the image
You now have the image to the correct size but for the web it is not really optimised.You now want to compress the image down from the current 4 bytes per pixel (32bit) image, which would be ~156KB (for a 200x200 image!). Time to compress:
private byte[] GetCroppedImage(byte[] originalBytes, Size size, ImageFormat format) { using (var streamOriginal = new MemoryStream(originalBytes)) using (var imgOriginal = Image.FromStream(streamOriginal)) { //get original width and height of the incoming image var originalWidth = imgOriginal.Width; // 1000 var originalHeight = imgOriginal.Height; // 800 //get the percentage difference in size of the dimension that will change the least var percWidth = ((float)size.Width / (float)originalWidth); // 0.2 var percHeight = ((float)size.Height / (float)originalHeight); // 0.25 var percentage = Math.Max(percHeight, percWidth); // 0.25 //get the ideal width and height for the resize (to the next whole number) var width = (int)Math.Max(originalWidth * percentage, size.Width); // 250 var height = (int)Math.Max(originalHeight * percentage, size.Height); // 200 //actually resize it using (var resizedBmp = new Bitmap(width, height)) { using (var graphics = Graphics.FromImage((Image)resizedBmp)) { graphics.InterpolationMode = InterpolationMode.Default; graphics.DrawImage(imgOriginal, 0, 0, width, height); } //work out the coordinates of the top left pixel for cropping var x = (width - size.Width) / 2; // 25 var y = (height - size.Height) / 2; // 0 //create the cropping rectangle var rectangle = new Rectangle(x, y, size.Width, size.Height); // 25, 0, 200, 200 //crop using (var croppedBmp = resizedBmp.Clone(rectangle, resizedBmp.PixelFormat)) using (var ms = new MemoryStream()) { //get the codec needed var imgCodec = ImageCodecInfo.GetImageEncoders().First(c => c.FormatID == format.Guid); //make a paramater to adjust quality var codecParams = new EncoderParameters(1); //reduce to quality of 80 (from range of 0 (max compression) to 100 (no compression)) codecParams.Param[0] = new EncoderParameter(Encoder.Quality, 80L); //save to the memorystream - convert it to an array and send it back as a byte[] croppedBmp.Save(ms, imgCodec, codecParams); return ms.ToArray(); } } } }
There you go. Your massive image is looking good to the correct size whilst being a much leaner version of former self. Congratulations!