What is it for?

When I'm looking for an image to use on my blog posts, I use this tool i created to search the best free stock image sites in one place. When I find an image I like, I download it and use it as the header image of my blog post. These images are usually 4000 pixels wide or more and take up unnecessary space on the server because I never display images wider than 1920 pixels on my site.

This post shows you how you can add a class to your umbraco project which automatically resizes any new images in Umbraco. You can choose whats size you want it to be and if you want it to upscale smaller images or not. You need to add the following appSetting values to your web.config file:

App Settings

<add key="ImageResizeWidth" value="1920" />
<add key="ImageResizeHeight" value="1080" />
<add key="ImageResizeSuffix" value="1080p" />
<add key="ImageResizeKeepOriginal" value="false" />
<add key="ImageResizeUpscale" value="true" />

Add this class in your project, I've put it in a library project which is reference by the web project. You could add it in the App_Code section if you don't have a separate library. Make sure you rename the namespace.

You can get it to add a resized version of the image and leave the original unchanged, or you can get it to replace them.

The MediaEventHandler Class

using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Services;
using Umbraco.Core.Models;
using ImageProcessor.Imaging;
using System.IO;
using System.Web.Configuration;
using System.Web;
using ImageProcessor;

namespace CodeShare.Library.EventHandlers
{
    public class MediaEventHandler : ApplicationEventHandler
    {
        protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {
            MediaService.Saving += MediaService_Saving;
        }

        /// <summary>
        /// This is called when media items are being saved. It loads the settings from the config appSettings.
        /// Depending on the settings, it create a resized version of the images and optionally replace the original files.
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Event arguments</param>
        private void MediaService_Saving(IMediaService sender, SaveEventArgs<IMedia> e)
        {
            int width = int.Parse(WebConfigurationManager.AppSettings["ImageResizeWidth"]);
            int height = int.Parse(WebConfigurationManager.AppSettings["ImageResizeHeight"]);
            string fileNameSuffix = WebConfigurationManager.AppSettings["ImageResizeSuffix"];
            bool keepOriginal = bool.Parse(WebConfigurationManager.AppSettings["ImageResizeKeepOriginal"]);
            bool upscale = bool.Parse(WebConfigurationManager.AppSettings["ImageResizeUpscale"]);

            foreach (IMedia mediaItem in e.SavedEntities)
            {
                if(!string.IsNullOrEmpty(mediaItem.ContentType.Alias) && mediaItem.ContentType.Alias.ToLower() == "image")
                {
                    bool isNew = mediaItem.Id <= 0;
                    int currentWidth = int.Parse(mediaItem.Properties["umbracoWidth"].Value.ToString());
                    int currentHeight = int.Parse(mediaItem.Properties["umbracoHeight"].Value.ToString());
                    bool isDesiredSize = (currentWidth == width) && (currentHeight == height);
                    bool isLargeEnough = currentWidth >= width && currentHeight >= height;
                    if (isNew && !isDesiredSize && (isLargeEnough || upscale))
                    {
                        string filePath = (string)mediaItem.Properties["umbracoFile"].Value;
                        string originalFilePath = HttpContext.Current.Server.MapPath(filePath);
                        string newFilePath = GetNewFilePath(originalFilePath, fileNameSuffix);
                        if (CreateCroppedImage(originalFilePath, newFilePath, width, height))
                        {
                            if (!keepOriginal)
                            {
                                if (DeleteFile(originalFilePath))
                                {
                                    RenameFile(newFilePath, originalFilePath);
                                }
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Creates a cropped version of the image at the size specified in the parameters
        /// </summary>
        /// <param name="originalFilePath">The full path of the original file</param>
        /// <param name="newFilePath">The full path of the new file</param>
        /// <param name="width">The new image width</param>
        /// <param name="height">The new image height</param>
        /// <returns>A bool to show if the method was successful or not</returns>
        private bool CreateCroppedImage(string originalFilePath, string newFilePath, int width, int height)
        {
            bool success = false;
            try
            {
                ImageFactory imageFactory = new ImageFactory();
                imageFactory.Load(originalFilePath);
                ResizeLayer layer = new ResizeLayer(new System.Drawing.Size(width, height), ResizeMode.Crop, AnchorPosition.Center);

//Performs auto-rotation to ensure that EXIF defined rotation is reflected in the final image.
imageFactory.AutoRotate();

                imageFactory.Resize(layer);
                imageFactory.Save(newFilePath);
                success = true;
            }
            catch (System.Exception)
            {
                success = false;
            }
finally
{
imageFactory.Dispose();
}
            return success;
        }

        /// <summary>
        /// Creates a new file path using the original one and adding a suffix to the file name
        /// </summary>
        /// <param name="filePath">The full path of the original file</param>
        /// <param name="fileNameSuffix">The suffix to be used at the end of the file name in the new file path</param>
        /// <returns>The new file path</returns>
        public string GetNewFilePath(string filePath, string fileNameSuffix)
        {
            FileInfo fileInfo = new FileInfo(filePath);
            string folderPath = fileInfo.DirectoryName;
            string fileExtension = fileInfo.Extension;
            string fullFileName = fileInfo.Name;
            string fileNameWithoutExtension = fullFileName.Substring(0, fullFileName.Length - fileExtension.Length);
            return string.Format("{0}\\{1}{2}{3}", folderPath, fileNameWithoutExtension, fileNameSuffix, fileExtension);
        }

        /// <summary>
        /// Deletes a file, if it exists
        /// </summary>
        /// <param name="filePath">The full path of the file to delete</param>
        /// <returns>A bool to show if the method was successful or not</returns>
        public bool DeleteFile(string filePath)
        {
            bool success = false;
            try
            {
                if(System.IO.File.Exists(filePath))
                {
                    System.IO.File.Delete(filePath);
                }
                success = true;
            }
            catch (System.Exception)
            {
                success = false;
            }
            return success;
        }

        /// <summary>
        /// Renames a file by using the Move method.
        /// </summary>
        /// <param name="sourceFileName">The full path of the source file</param>
        /// <param name="destFileName">The full path of the destination file</param>
        /// <returns>A bool to show if the method was successful or not</returns>
        public bool RenameFile(string sourceFileName, string destFileName)
        {
            bool success = false;
            try
            {
                if (System.IO.File.Exists(sourceFileName) && !System.IO.File.Exists(destFileName))
                {
                    System.IO.File.Move(sourceFileName, destFileName);
                    success = true;
                }
            }
            catch (System.Exception)
            {
                success = false;
            }
            return success;
        }
    }
}

Let me know how you get on

If you like this or use it, let me know. Share it with others if it is of any use. It's free for you to use however you want.

Want to thank me?

If I've helped you out and you want to thank me, why not buy me a coffee?

About the author

Paul Seal

Umbraco MVP and .NET Web Developer from Derby (UK) who specialises in building Content Management System (CMS) websites using MVC with Umbraco as a framework. Paul is passionate about web development and programming as a whole. Apart from when he's with his wife and son, if he's not writing code, he's thinking about it or listening to a podcast about it.

Related Posts

How to fix corrupt accented characters in Excel for a C# export as CSV

This post will help you fix the issue where you csv export has corrupt characters when opening it in…

Read Post

How to create a dynamic image from multiple images using ImageProcessor

This post shows you how I created a handler to create dynamic header images for my umbraco website u…

Read Post

How to send Slack messages programmatically using C#

In this post I show you how you can send Slack messages programmatically using C#

Read Post

How to fix the SVG 404 error when using Umbraco and Azure Blob Storage

In this post I show you how to solve the SVG 404 error when working with Umbraco and Azure Blob Stor…

Read Post