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!
A quick warning to everybody thinking about using System.Drawing (or GDI+) in an ASP.NET environment. It's not supported by Microsoft and MSDN (as of recently) clearly states that you may experience memory leaks.
ReplyDeleteClearly GDI+ is a legacy API and one should opt for image processing using WPF in general.
Here's a quote from http://msdn.microsoft.com/en-us/library/system.drawing.aspx:
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions. For a supported alternative, see Windows Imaging Components.
Cool. I've never heard of WIC so it sounds interesting and I'll have a look.
ReplyDeleteJust to make clear the code above isn't thrown together. It evolved with time because as you suggested it is too easy to mistakenly create performance issues when using GDI+. Just see how many times I've written 'using' above!
Anyway, please be assured the above code is highly optimised and tested and has run successfully in a high traffic production environment for a few months now.
Excellent! Thanks for sharing Colin!
ReplyDelete@Anders Borum: Actually, despite what MSDN (incorrectly) states, WIC is NOT supported for use within an ASP.NET service. As WPF wraps WIC, it is subject to the same problems WIC faces. WIC is also only available on Server 2008 and higher, instability will result on OSes where WIC MTA threading isn't available.
ReplyDeleteYou can read it for yourself (Note #2) at the end of this MS blog: http://weblogs.asp.net/bleroy/archive/2009/12/10/resizing-images-from-the-server-using-wpf-wic-instead-of-gdi.aspx
Also, using WPF or WIC will require you place the entire ASP.NET app in Full Trust mode, destroying any sandbox-level security you would have had. GDI works properly even on low-trust scenarios.
--------
To all readers.
Take a look at http://imageresizing.net/
It's free, it's open, and it's reliable. It's fast, well tested, and refined. It even has a NuGet package. And it is thoroughly documented. What are you waiting for?
BUT - If you don't like using existing code, well tested libraries, or simply enjoy the Windows API so much you HAVE to write your own image resizing module, please read the list of pitfalls you need to avoid (these were compiled over many years and many versions of the aforementioned library).
http://nathanaeljones.com/163/20-image-resizing-pitfalls/
Hope this helps!
Nathanael Jones
Nice one.....
ReplyDeletei have been looking for this thx dude
Great Work... Thanks...very very much
ReplyDeleteThanks! It works great!
ReplyDeleteThanks. It works just great!
ReplyDeleteThis is what I need! It works great for me. Thank you!
ReplyDeleteinstagram search
Motifz Designer Lawn. 1, 2 & 3 Piece Unstitched Premium Embroidered Lawn 2019, Premium embroidered Lawn, Premium lawn, Premium lawn 2019, Motifz, Premium lawn in Pakistan Summer collection. Shipping worldwide. Stitching option available.
ReplyDeleteIt is really nice to get the instructions of Image functionalities using the .NET.
ReplyDeleteDo you know? Data breaches on personal computers cause harms to individuals identity, to prevent such attacks use McAfee antivirus and if you want to make sure it is worth it, then take the McAfee Free Trial
McAfee antivirus allows you to protect your computer from suspicious malwares and keep your files safe. Visit mcafee.com/activate
ReplyDeleteand activate your antivirus.
mcafee.com/activate
www.mcafee.com
www.mcafee.com/activate
Really very happy to say, your post is very interesting to read. You’re doing a great job. Keep it up, and also visit our site to get latest news about Marvel Studios and their actress.
ReplyDeleteIron Man Armour
Avengers Endgame
Are you interested more to know about how to Update Garmin GPS easily? For detailed information please visit our website or call us.
ReplyDeleteit was a wonderful chance to visit this kind of site and I am happy to know. thank you so much for giving us a chance to have this opportunity.. videoproduktion
ReplyDeleteFor such purposes a good web connection is required with stable speed in order to buffer the video or the movie efficiently. Moreover, online movie download features are also available via proper subscription to such legit sites.
ReplyDeleteffmovie
Social media is an inexpensive way to get the word out about your movie and create a killer viral buzz online.123movie
ReplyDeleteEquipment from these kind of providers are inexpensive, usually is not commercial grade (but rather equipment meant for personal use) or that is under-powered for an outdoor movie setting. Their equipment is really ment for indoor movie events.
ReplyDelete123 movies
Every single person involved in the making of your film has a story and an angle you can pursue media.0123movies
ReplyDeleteAnd this ties in that a time will come when audiences will grow out of movies which rely on special effects and big star names to entertain and start turning there back on movies which have no originality or fail to deliver a different angle on an old storyline.
ReplyDelete0123movie
حمل بار
ReplyDeleteBuy online wholesale printed candle boxes and packaging at easy prices and shipping worldwide, with 24/7 customer support. Get a free custom quote now!!
ReplyDeleteBuy online wholesale printed custom candle boxes and packaging at easy prices and shipping worldwide, with 24/7 customer support. Get a free custom quote now!!
ReplyDelete
ReplyDeletefmovies
xmovies8
0123moviesfree
Cloud Computing Projects
ReplyDeleteNetworking Projects
Final Year
Projects for CSE
JavaScript Training in Chennai
JavaScript
Training in Chennai
The Angular Training covers a wide range of topics including Components, Angular Directives, Angular Services, Pipes, security fundamentals,
Routing, and Angular programmability. The new Angular TRaining will lay the foundation you need to specialise in Single Page Application developer.
Angular Training
Hey what a brilliant post I have come across and believe me I have been searching out for this similar kind of post for past a week and hardly came across this. Thank you very much and will look for more postings from you Get for more information mahindra mini tractor
ReplyDeleteBlackbird packaging provide you with any size, shape design, custom bath bomb boxes sooner than any other packaging competitor in the market
ReplyDeleteIn a film democracy no filmmaker is safe from movie viewer salvos or roses being virtually thrown. I've read posts that start by tearing apart a movie until there is nothing left to attack. movie online 2021
ReplyDeleteFigure below shows a two-frame animation after four tween frames were added. The opacity of the man is 100% in the first frame and 0% in the last frame. Adding five tween frames causes the two images to blend into each other smoothly, or morph (metamorphose). gogo anime
ReplyDeleteThis post is very good I am very happy to see this post. Thanks for sharing such a wonderful article. keep up the work... your site is great, and it's helping us a lot.. this post is unique and interesting, thanks for sharing this awesome info
ReplyDeletemahindra tractors price
"I didn't realize how animal communication really works until just now. Someone can connect with my cat and read her thoughts and tell me how she's feeling and what she wants... ?! That's amazing! I live for the day when I can do that myself!" 9 anime
ReplyDeleteBecause both tasks access and use your intuition. They both require you to feel and open your senses. Furthermore, they both engage your creative imagination in unique ways. gogoanime - watch anime online
ReplyDeleteHighly sensitive empaths often feel overwhelmed by the world around them. You pick up too much information, feel drained, and often shut down your intuitive gifts and abilities entirely. 4anime
ReplyDeleteYour cat tells you I can feel a pressure growing inside my head, I can't see out of one eye, and the pain is becoming more than I can bear. 123movie
ReplyDeleteBy the 1970's, movie posters used photography, occasionally using drawing and painting styles. 4anime
ReplyDeleteBuy sports bra pakistan online online from ndure at easy prices delivered at your doorstep. Get free shipping
ReplyDeleteBuy gym trousers mens online pakistan from Dshred at best prices delivered at your doorstep. Get free shipping
ReplyDeleteSimply wish to claim ones document is usually as astonishing. This clearness with your write-up is usually simply great in addition to when i can think you are a pro within this theme. อ่านมังงะ
ReplyDeleteI'm impatient for one's then blog post, I値l have a shot at to see the stick of it! อ่านการ์ตูน
ReplyDeleteThis post is very good I am very happy to see this post. Thanks for sharing such a wonderful article. Find Affordable Property Lawyer
ReplyDeletegreat blog, thanks for sharing.
ReplyDeleteKubota Tractor
Thanks for sharing such a wonderful article.
ReplyDeleteRegards
Know my Pune
Hello!!
ReplyDeleteAmazing . Thank you for sharing with us.
tractor tyre 13.6 28 price goodyear
I'm very happy to say, your post is very interesting to read. You’re doing a great job.
ReplyDeleteOur Site
Thank you for sharing this insightful article! It provided me with a fresh perspective on the topic and expanded my understanding. Need writing help,Visit For More Info
ReplyDelete