find a location for property in a new city

Thursday 19 May 2011

Image resizing, cropping and compression using .NET

If you need to resize an image or crop an image or compress an image or even do all three you will find you can do all of those things using the .NET framework's System.Drawing classes. In this tutorial I will talk you through the steps required to do all three to transform an large image to an image fit for your website.

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!

Update

In line 24, you can see I have set the InterpoltionMode of the graphics object to InterpolationMode.HighQualityBicubic before doing the initial resize. I previously had this set to Default but I noticed that straight diagonal lines in resized images were coming out jagged and they didn't look pretty. HighQualityBicubic is meant to be "the best" form of interpolation according to Microsoft so I sided with that. I can see a big improvement in the quality so I would recommend it too.

Follow britishdev on Twitter

47 comments:

  1. 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.

    Clearly 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.

    ReplyDelete
  2. Cool. I've never heard of WIC so it sounds interesting and I'll have a look.

    Just 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.

    ReplyDelete
  3. Excellent! Thanks for sharing Colin!

    ReplyDelete
  4. @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.

    You 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

    ReplyDelete
  5. Nice one.....
    i have been looking for this thx dude

    ReplyDelete
  6. Great Work... Thanks...very very much

    ReplyDelete
  7. Thanks. It works just great!

    ReplyDelete
  8. This is what I need! It works great for me. Thank you!
    instagram search

    ReplyDelete
  9. 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.

    ReplyDelete
  10. It is really nice to get the instructions of Image functionalities using the .NET.
    Do 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

    ReplyDelete
  11. McAfee antivirus allows you to protect your computer from suspicious malwares and keep your files safe. Visit mcafee.com/activate
    and activate your antivirus.
    mcafee.com/activate
    www.mcafee.com
    www.mcafee.com/activate

    ReplyDelete
  12. 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.

    Iron Man Armour

    Avengers Endgame

    ReplyDelete
  13. Are you interested more to know about how to Update Garmin GPS easily? For detailed information please visit our website or call us.

    ReplyDelete
  14. it 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

    ReplyDelete
  15. For 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.
    ffmovie

    ReplyDelete
  16. Social media is an inexpensive way to get the word out about your movie and create a killer viral buzz online.123movie

    ReplyDelete
  17. Equipment 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.

    123 movies

    ReplyDelete
  18. Every single person involved in the making of your film has a story and an angle you can pursue media.0123movies

    ReplyDelete
  19. And 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.

    0123movie

    ReplyDelete
  20. Buy online wholesale printed candle boxes and packaging at easy prices and shipping worldwide, with 24/7 customer support. Get a free custom quote now!!

    ReplyDelete
  21. Buy 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
  22. Cloud Computing Projects




    Networking 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

    ReplyDelete
  23. 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

    ReplyDelete
  24. Blackbird packaging provide you with any size, shape design, custom bath bomb boxes sooner than any other packaging competitor in the market

    ReplyDelete
  25. In 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

    ReplyDelete
  26. Figure 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

    ReplyDelete
  27. This 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

    mahindra tractors price

    ReplyDelete
  28. "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

    ReplyDelete
  29. Because 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

    ReplyDelete
  30. Highly 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

    ReplyDelete
  31. Your 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

    ReplyDelete
  32. By the 1970's, movie posters used photography, occasionally using drawing and painting styles. 4anime

    ReplyDelete
  33. Buy sports bra pakistan online online from ndure at easy prices delivered at your doorstep. Get free shipping

    ReplyDelete
  34. Buy gym trousers mens online pakistan from Dshred at best prices delivered at your doorstep. Get free shipping

    ReplyDelete
  35. Simply 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. อ่านมังงะ

    ReplyDelete
  36. I'm impatient for one's then blog post, I値l have a shot at to see the stick of it! อ่านการ์ตูน

    ReplyDelete
  37. Your blogs are great. Are you also searching for Help with my Math assignment? we are the best solution for you. We are best known for delivering quality essay writing services to students without having to break the bank

    ReplyDelete
  38. I love this. It is soo informative. Are you also searching for cheap assignment writing services we are the best solution for you. We are best known for delivering the best services to students without having to break the bank

    ReplyDelete
  39. This post is very good I am very happy to see this post. Thanks for sharing such a wonderful article. Find Affordable Property Lawyer

    ReplyDelete
  40. Thanks for sharing such a wonderful article.
    Regards
    Know my Pune

    ReplyDelete
  41. I'm very happy to say, your post is very interesting to read. You’re doing a great job.
    Our Site

    ReplyDelete
  42. 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