Serving optimized images on websites is essential to get high performances website and get a good user experience. There are numerous implementations of this and here is yet another one. Inspired by Anders Laub previous posts on cropping and compressing images, I decided to make one that makes optimized progressive images.
Normal images are loaded from top to bottom, aka baseline images. The advantage of progressive images is that the entire image is shown almost right away, but the image is blurry at first when only a portion of the image is loaded and the image then becomes clearer as more image data is loaded in the browser. This makes the perceived load speed faster to the viewer.
Here is how a standard baseline image will load in a browser:
And here is how the same image will load in a browser when saved as progressive jpeg.
Leveraging from the Magick.Net library, a .Net port of the famous ImageMagick library, we can easily create optimized progressive images and gain quite good server rendering performance as well. By hooking into the <getMediaStream>
pipeline, we can just add a processor for cropping and one for saving the image. By doing so, we’ll also leverage from Sitecore built-in disk cache for resized images. This means the CPU heavy creation of the images will only be performed once.
Later versions of Sitecore (7.5+) requires a hash code in the image URL to prevent Denial of Service attacks. One could send a lot of requests to the servers and alter the requested image width or height with just one pixel and that would cause Sitecore to generate a new image for every new unique request. The hash code prevents this by ignoring the parameters and just send the original file when the hash parameter is missing or incorrect. It’s therefore important that we add our custom cropping and quality parameters to the media library <protectedMediaQueryParameters>
list. And as always, HashingUtils.ProtectAssetUrl
needs to be called when creating the image urls.
It’s important to verify that images are scaled properly, since rendering a page with incorrect or missing hashes may not be clearly visible to the human eye.
Sitecore Nuget
Sitecore has finally provided a official Nuget feed. If you’re not using it already, add the feed to your Package Sources list in Visual Studio. The Sitecore Official feed is available here https://sitecore.myget.org/F/sc-packages/api/v3/index.json
for Visual Studio 2015+. If you’re using an older version (VS 2012+) you’ll need to use this NuGet V2 feed: https://sitecore.myget.org/F/sc-packages/
The feed contains Sitecore packages from 7.2 and upwards and packages are provided in alternative variants, such as component packages, single assembly packages with references and single assembly packages with no references. I find the last one very attractive when distributing small modules, such as this one.
The code
Feel free to grab the code from github: https://github.com/mikaelnet/sitecore-imaging. It’s currently linked to Sitecore 8.2, but you can change the version reference to fit your solution. You may also want to change the Magick.Net reference to fit your environment, but make sure you reference a late version that isn’t linked to a Image Tragick vulnerable version of ImageMagick.
The cropper processor uses the cw
and ch
parameters to set a crop width and height. The progressive jpeg processor uses the jq
parameter to set jpeg quality between 0 and 100.
Using the library is pretty straight forward. You can either create bare metal URLs by just appending the query string parameters you want and wrap it in HashingUtils.ProtectAssetUrl
. Alternatively, you can use the fluent ImageRendering helper class to chain image commands, such as imageRendering.WithAutoCrop(400,300).WithQuality(75).GetUri()
and so on.
Enjoy!