Resize image to be web friendly

There’s already a post about this subject on the blog but it is in italian, I want to propose it again because the task of resizing and slim the pictures we got (for facebook, for our blog) is a common task we are all used to. Here’s the code and a small console app you can use for this purpose, it is very easy to use: set the path of the input folder, the desired quality and resolution for the output and wait for the app to convert the images. Below the code and a couple of screenshoots of the app:

class Program
{
    static void Main(string[] args)
    {
        Console.Write(@"Select input folder (ie: c:\images):");
        string folder = Console.ReadLine();
        Console.Write("Choose image height(ie: 1024) :");
        int width = Convert.ToInt32(Console.ReadLine());
        Console.Write("Choose image width (ie: 768) :");
        int height = Convert.ToInt32(Console.ReadLine());
        Console.Write("Choose quality (0 - 100):");
        int quality = Convert.ToInt32(Console.ReadLine());
        string newFolder = folder + "_resized";
        Console.Write("Output folder will be: {0}", newFolder);
        Console.Write("Please wait until the conversion is complete.");
        List<string> files = Directory.GetFiles(folder).ToList();
        Directory.CreateDirectory(newFolder);
        foreach (string file in files)
        {
            ImageUtilities.ResizeImage(file, (newFolder + "\\" + Path.GetFileName(file)), width, height, true, quality);
        }
        Console.WriteLine("Done!");
        Console.WriteLine("Press any key to exit");
        Console.ReadLine();
    }

}
/// <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 quick lookup for getting image encoders
    /// </summary>
    public static Dictionary<string, ImageCodecInfo> Encoders
    {
        //get accessor that creates the dictionary on demandd
        get
        {
            //if the quick lookup isn't initialised, initialise it
            if (encoders == null)
            {
                encoders = new Dictionary<string, ImageCodecInfo>();
            }

            //if there are no codecs, try loading them
            if (encoders.Count == 0)
            {
                //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;
        }
    }

    public static void ResizeImage(string OriginalFile, string NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider, int quality)
    {
        System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFile);

        // Prevent using images internal thumbnail
        FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
        FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);

        if (OnlyResizeIfWider)
        {
            if (FullsizeImage.Width <= NewWidth)
            {
                NewWidth = FullsizeImage.Width;
            }
        }

        int NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
        if (NewHeight > MaxHeight)
        {
            // Resize with height instead
            NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
            NewHeight = MaxHeight;
        }

        System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);

        // Clear handle to original file so that we can overwrite it if necessary
        FullsizeImage.Dispose();

        // Save resized picture
        //NewImage.Save(NewFile);
        SaveJpeg(NewFile, NewImage, quality);
    }

    /// <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 look at the mime type
        mimeType = mimeType.ToLower();

        //the codec to return, default to null
        ImageCodecInfo foundCodec = null;

        //if we have the encoder, get it to return
        if (Encoders.ContainsKey(mimeType))
        {
            //pull the codec from the lookup
            foundCodec = Encoders[mimeType];
        }

        return foundCodec;
    }
}

image image

Here’s the console app.

Create an image from text (Updated)

I’ve done a few changes and some additions on the code of the previous post.

The CreateTextImage now prints the text at the center of the image, this is done using the Alignment property of the StringFormat class:

public Bitmap CreateTextImage(string imageText)
{
    Bitmap outputImage = new Bitmap(1, 1);
    int imageWidth, imageHeight = 0;

    //setup the font
    Font imageFont = new Font("Arial", 25, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel);

    StringFormat stringFormat = new StringFormat();
    stringFormat.Alignment = StringAlignment.Center;
    stringFormat.LineAlignment = StringAlignment.Center;

    //using graphic to mesure text and create again the image with the correct size 
    Graphics imageGraphics = Graphics.FromImage(outputImage);
    imageWidth = (int)imageGraphics.MeasureString(imageText, imageFont).Width + 80;
    imageHeight = (int)imageGraphics.MeasureString(imageText, imageFont).Height + 80;
    outputImage = new Bitmap(outputImage, new Size(imageWidth, imageHeight));

    //manage colors
    imageGraphics = Graphics.FromImage(outputImage);

    //background
    imageGraphics.Clear(Color.White);
    imageGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    imageGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
           imageGraphics.DrawString(imageText, imageFont, new SolidBrush(Color.Black), new RectangleF(0,0,imageWidth,imageHeight), stringFormat);
    imageGraphics.Flush();

    return outputImage;
}

Some extensions methods for the Bitmap class, adding the chance to save te image as a JPEG and set the quality of the output:

public static class BitmapExtensions
{
    public static void SaveJPG100(this Bitmap bmp, string filename)
    {
        EncoderParameters encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
        bmp.Save(filename, GetEncoder(ImageFormat.Jpeg), encoderParameters);
    }

    public static void SaveJPG100(this Bitmap bmp, Stream stream)
    {
        EncoderParameters encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
        bmp.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
    }

    public static void SaveJPGCustomQuality(this Bitmap bmp, string filename, Int64 quality)
    {
        EncoderParameters encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
        bmp.Save(filename, GetEncoder(ImageFormat.Jpeg), encoderParameters);
    }

    public static void SaveJPGCustomQuality(this Bitmap bmp, Stream stream, Int64 quality)
    {
        EncoderParameters encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
        bmp.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
    }

    public static ImageCodecInfo GetEncoder(ImageFormat format)
    {
        ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
        foreach (ImageCodecInfo codec in codecs)
        {
            if (codec.FormatID == format.Guid)
            {
                return codec;
            }
        }
        return null;
    }
}