Search code examples
c#imageimage-processingimage-manipulationimage-scaling

High Quality Image Scaling Library


I want to scale an image in C# with quality level as good as Photoshop does. Is there any C# image processing library available to do this thing?


Solution

  • Here's a nicely commented Image Manipulation helper class that you can look at and use. I wrote it as an example of how to perform certain image manipulation tasks in C#. You'll be interested in the ResizeImage function that takes a System.Drawing.Image, the width and the height as the arguments.

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    
    namespace DoctaJonez.Drawing.Imaging
    {
        /// <summary>
        /// Provides various image untilities, such as high quality resizing and the ability to save a JPEG.
        /// </summary>
        public static class ImageUtilities
        {    
            /// <summary>
            /// A quick lookup for getting image encoders
            /// </summary>
            private static Dictionary<string, ImageCodecInfo> encoders = null;
    
            /// <summary>
            /// A lock to prevent concurrency issues loading the encoders.
            /// </summary>
            private static object encodersLock = new object();
    
            /// <summary>
            /// A quick lookup for getting image encoders
            /// </summary>
            public static Dictionary<string, ImageCodecInfo> Encoders
            {
                //get accessor that creates the dictionary on demand
                get
                {
                    //if the quick lookup isn't initialised, initialise it
                    if (encoders == null)
                    {
                        //protect against concurrency issues
                        lock (encodersLock)
                        {
                            //check again, we might not have been the first person to acquire the lock (see the double checked lock pattern)
                            if (encoders == null)
                            {
                                encoders = new Dictionary<string, ImageCodecInfo>();
    
                                //get all the codecs
                                foreach (ImageCodecInfo codec in ImageCodecInfo.GetImageEncoders())
                                {
                                    //add each codec to the quick lookup
                                    encoders.Add(codec.MimeType.ToLower(), codec);
                                }
                            }
                        }
                    }
    
                    //return the lookup
                    return encoders;
                }
            }
    
            /// <summary>
            /// Resize the image to the specified width and height.
            /// </summary>
            /// <param name="image">The image to resize.</param>
            /// <param name="width">The width to resize to.</param>
            /// <param name="height">The height to resize to.</param>
            /// <returns>The resized image.</returns>
            public static System.Drawing.Bitmap ResizeImage(System.Drawing.Image image, int width, int height)
            {
                //a holder for the result
                Bitmap result = new Bitmap(width, height);
                //set the resolutions the same to avoid cropping due to resolution differences
                result.SetResolution(image.HorizontalResolution, image.VerticalResolution);
    
                //use a graphics object to draw the resized image into the bitmap
                using (Graphics graphics = Graphics.FromImage(result))
                {
                    //set the resize quality modes to high quality
                    graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                    graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    //draw the image into the target bitmap
                    graphics.DrawImage(image, 0, 0, result.Width, result.Height);
                }
    
                //return the resulting bitmap
                return result;
            }
    
            /// <summary> 
            /// Saves an image as a jpeg image, with the given quality 
            /// </summary> 
            /// <param name="path">Path to which the image would be saved.</param> 
            /// <param name="quality">An integer from 0 to 100, with 100 being the 
            /// highest quality</param> 
            /// <exception cref="ArgumentOutOfRangeException">
            /// An invalid value was entered for image quality.
            /// </exception>
            public static void SaveJpeg(string path, Image image, int quality)
            {
                //ensure the quality is within the correct range
                if ((quality < 0) || (quality > 100))
                {
                    //create the error message
                    string error = string.Format("Jpeg image quality must be between 0 and 100, with 100 being the highest quality.  A value of {0} was specified.", quality);
                    //throw a helpful exception
                    throw new ArgumentOutOfRangeException(error);
                }
    
                //create an encoder parameter for the image quality
                EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
                //get the jpeg codec
                ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
    
                //create a collection of all parameters that we will pass to the encoder
                EncoderParameters encoderParams = new EncoderParameters(1);
                //set the quality parameter for the codec
                encoderParams.Param[0] = qualityParam;
                //save the image using the codec and the parameters
                image.Save(path, jpegCodec, encoderParams);
            }
    
            /// <summary> 
            /// Returns the image codec with the given mime type 
            /// </summary> 
            public static ImageCodecInfo GetEncoderInfo(string mimeType)
            {
                //do a case insensitive search for the mime type
                string lookupKey = mimeType.ToLower();
    
                //the codec to return, default to null
                ImageCodecInfo foundCodec = null;
    
                //if we have the encoder, get it to return
                if (Encoders.ContainsKey(lookupKey))
                {
                    //pull the codec from the lookup
                    foundCodec = Encoders[lookupKey];
                }
    
                return foundCodec;
            } 
        }
    }
    

    Update

    A few people have been asking in the comments for samples of how to consume the ImageUtilities class, so here you go.

    //resize the image to the specified height and width
    using (var resized = ImageUtilities.ResizeImage(image, 50, 100))
    {
        //save the resized image as a jpeg with a quality of 90
        ImageUtilities.SaveJpeg(@"C:\myimage.jpeg", resized, 90);
    }
    

    Note

    Remember that images are disposable, so you need to assign the result of your resize to a using declaration (or you could use a try finally and make sure you call dispose in your finally).