Image optimization

In Kentico 12 using ImageMagick

Optimizing, free of charge

Hey guys! After my previous post about image optimization with TinyPNG service I have received a few comments, like:

This is a really nice way of image optimizing, but.. what if we have a lot of images and can't pay the subscription?

Well, it should still be possible, I thought. There are some free libraries doing image optimization. And one of the best I have ever seen is Magick.NET (.NET implementation of very popular ImageMagick library). And now there is another Nuget package for Kentico that just does the job.

Installation

Pretty simple process. Install the Nuget package:

Install-Package DeleteAgency.Kentico12.ImageMagick

If your project is MVC, you should install this package for both CMS and MVC solutions (in order to support images optimization for Media Selector introduced in Kentico 12 Service Pack)! Build and run your CMS project. After the first run the following settings will appear automatically:

And then just tick "Enabled" checkbox and start uploading images!

A few examples of images with default optimization applied (yes, these are cats again):

JPEG
Original image: 2.8 MB
Optimized image: 0.57 MB

PNG
Original image: 1.9 MB
Optimized image: 0.26 MB

Customizing

The module allows a few settings by default, but the key one is Image Quality. It is set to 60% by default. I have run a few tests and found this value is the best compromize between file size and image quality.

Also, the default optimization:

  • Converts all JPEGs to progressive JPEGs
  • Converts all PNG files to 8-bit PNGs (that are much better for web but also it leads to change in colours a little)

But this all can be easily customized: if there is a need for any other manipulation with image - just implement IOptimization interface dealing with MagickImage object and set it on the website start (via custom module, for example):

[assembly: RegisterModule(typeof(CustomModule))]
namespace CMSApp.CMSModules
{
    public class CustomModule : Module
    {
        public CustomModule() : base("CustomModule", true)
        {
        }

        protected override void OnInit()
        {
            base.OnInit();

            ImageMagickImageOptimizer.SetOptimization(new CustomOptimization());
        }
    }

    public class CustomOptimization : IOptimization
    {
        public void Apply(MagickImage image)
        {
            switch (image.Format)
            {
                // Make all JPEGs progressive
                case MagickFormat.Jpe:
                case MagickFormat.Jpeg:
                case MagickFormat.Jpg:
                    image.Format = MagickFormat.Pjpeg;
                    break;

                // Normalize all PNG formats
                case MagickFormat.Png:
                case MagickFormat.Png8:
                case MagickFormat.Png00:
                case MagickFormat.Png24:
                case MagickFormat.Png32:
                case MagickFormat.Png48:
                case MagickFormat.Png64:
                    image.Format = MagickFormat.Png;
                    break;
            }

            // Remove meta information
            image.Strip();

            // Decrease image quality
            image.Quality = 80;
        }
    }
}

And there are a few image optimization events to support more customization (like I mentioned in my previous post):

[assembly: RegisterModule(typeof(CustomModule))]
namespace CMSApp.CMSModules
{
    public class CustomModule : Module
    {
        public CustomModule() : base("CustomModule", true)
        {
        }

        protected override void OnInit()
        {
            base.OnInit();

            ImageMagickImageOptimizer.Events.Before += ImageMagickEvent;
            ImageMagickImageOptimizer.Events.After += ImageMagickEvent;
            ImageMagickImageOptimizer.Events.Error += ImageMagickEvent;
        }

        private void ImageMagickEvent(object sender, ImageMagickImageOptimizerEventArgs e)
        {
            // do something
        }
    }
}

Wrapping up

The code of the module can be found on the GitHub. Contributions are welcomed!

From my experience, automatic services like TinyPNG would still be a better solution because they are completely automatic. With libraries like ImageMagick you should know a bit of image optimization basics to write a perfect optimizer for your specific needs. Happy coding!