Image optimization

In Kentico 12 using TinyPNG API

Update

The updated Nuget package now supports the optimization of Page Attachmets as well!

Update 2

After Kentico 12 Service Pack realease you should install the nuget package for both CMS and MVC projects.

Update 3

Very strangely, our account in Nuget was dropped and the version of Nuget package is unlisted now. I have republished it with changed name: DeleteAgency.Kentico12.TinyPng. All the references in the article have been updated.

The problem

It happens all the time! You develop a great website with lots of business-critical features and outstanding performance. You optimize the page loading speed fighting for every single kilobyte. Then, it comes to the content population. And all your efforts are being ruined by 15 MB high resolution image placed in the hero banner of the home page!

So, the first thing you might try to do is to explain your content managers the neccessity of optimizing images before uploading into the website. But this will just add an extra routine into their everyday work. We are programmers and we will automate this instead!

Meet TinyPNG

TinyPNG service allows you to shrink, resize and crop PNG and JPEG images. You can do it manually via the portal or integrate with their API. The beauty of the service is that it allows 500 image optimizations per month for free! Which is usually more than enough for a middle-tier website. There is also a price calculator for API usage on this page if you plan to use more.

For easier integration with TinyPNG service I have developed a module. This module will shrink image via TinyPNG API every time you upload or update the image in the Media Library. To install it  from Nuget just type:

Install-Package DeleteAgency.Kentico12.TinyPng

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:

To enable this module just tick "Enabled" setting and paste your TinyPNG API Key (to obtain the API key you only need to register with your name and email address, no payment method required). That's it! From now on your website will shrink the images automatically when the content editor will upload them!

Examples

Here are a couple of high resolution cat images found in the Internet. And how they were shrinked with this module. Would you tell the difference in how they look? But the size has been reduced dramatically!

JPEG
Original image: 2.8 MB
Optimized image: 0.43 MB

PNG
Original image: 1.9 MB
Optimized image: 0.4 MB

OOTB Image Optimization

Kentico comes with out-of-the-box image optimization options. Each has some limitations you should be aware of before using it.

Resizing images on load. Will shrink you file during uploading to prevent exceeding some specified maximum width or height value. Will not keep your original image resolution if it exceeds the maximum value and will not optimize images when their width or height lower than specified maximum.

Responsive images. Really good and interesting feature. Unfortunately, works only with page attachments and doesn't work with Media Libraries.

Width and height URL parameters. Very convenient feature especially when you display images via srcsets. And for the best results it's possible to combine this one with the approach described in this article! For example, you can get these results after applying ?width=300 parameter:

JPEG
Original image (300 px width): 19.445 KB
Optimized image (300 px width): 19.419 KB

PNG
Original image (300 px width): 38.518 KB
Optimized image (300 px width): 10.639 KB

Dive into the code

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

Apart from just optimizing the images, the module provides 3 events to subscribe:

  • TinyPngImageOptimizer.Events.Before
    Fires before image optimization. You can cancel optimization by setting e.CancelImageOptimization = true;
  • TinyPngImageOptimizer.Events.After
    Fires after image optimization. TinyPngImageOptimizerEventArgs object contains some information about optimization: original and optimized size, image ratio, etc. 
  • TinyPngImageOptimizer.Events.Error
    Fires when there was an error during optimization. Ideal place for logging this event in Kentico.

What else could you do with this? For example, you can add "IsOptimized" custom property into MediaFileInfo class (which is customizable in Kentico) and shrink images only once. The following code example shows how to do it:

using CMS;
using CMS.DataEngine;
using CMSApp.CMSModules;
using Delete.Kentico12.TinyPng;
using Delete.Kentico12.TinyPng.Events;

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

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

            TinyPngImageOptimizer.Events.Before += BeforeImageOptimization;
            TinyPngImageOptimizer.Events.After += AfterImageOptimization;
        }

        private void AfterImageOptimization(object sender, TinyPngImageOptimizerEventArgs e)
        {
            if (e.MediaFile != null && e.ImageOptimizationSuccessful)
            {
                e.MediaFile.SetValue("IsOptimized", true);
            }
        }

        private void BeforeImageOptimization(object sender, TinyPngImageOptimizerEventArgs e)
        {
            // If file binary is updated
            if (e.MediaFile?.FileBinary != null) return;

            if (e.MediaFile != null && e.MediaFile.GetBooleanValue("IsOptimized", false))
            {
                e.CancelImageOptimization = true;
            }
        }
    }
}

Conclusion

It goes without saying that image optimization is really important for the website. With my module and TinyPNG service it's very easy to start. Happy coding!