Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • schlubadub 102 posts 617 karma points
    Apr 15, 2015 @ 05:19
    schlubadub
    0

    Umbraco 7 Image Resizing (Media Library & RTE)

    Can anyone tell me how Umbraco is handling large image resizing out of the box? I have users uploading massive images (e.g. 6000 x 3656) and standard behaviour in a CMS is to process these images in some way before they hit the server. At the very least, I want these resized to say 1200px wide before being stored.

    Note: I am aware of the ImageProcessor, but that does POST processing of images via parameters which is great, but I also want to pre-process the image sizes automatically.

    I want to control the uploaded size for 3 reasons: 1) to constrain the amount of storage each client uses; 2) to reduce the amount of server overhead reducing massive images down (even if they are cached); 3) to provide a more "fool proof" experience by only having images selectable that are a reasonable size and can't totally destroy a page layout when something goes awry.

    Regarding the Grid RTE - I have set the max image size (under the appropriate Umbraco.Grid data type) at 1024px wide but when images are added via the RTE it is NOT being used anywhere as the images are still full size and there are no ImageProcessor parameters in place. How is this supposed to be applied? I've used the Fanoe starter pack, if that makes any difference. I've tried uploading the images beforehand and within the RTE, but the results are the same.

    In an ideal world all of my users will know everything about image resizing beforehand, but we all know that won't happen anytime soon!

    Note: I'm not really referring to the Grid Images as I can always use "Image Cropper" or Grid config sizes there. It's only the images in the Media library that need further treatment.

  • Jan Skovgaard 11280 posts 23678 karma points MVP 10x admin c-trib
    Apr 15, 2015 @ 05:49
    Jan Skovgaard
    2

    Hi Schlubadub

    Perhaps you can benefit from pre-processing the images using ImageProcessor? James South wrote about this in last years annual Umbraco advent calendar http://24days.in/umbraco/2014/all-your-images-are-belong-to-umbraco/

    I think you should be able to handle the resizing on the fly when uploading using this technique.

    Hope this helps.

    /Jan

  • schlubadub 102 posts 617 karma points
    Apr 15, 2015 @ 09:02
    schlubadub
    0

    Thanks Jan, that certainly looks like it will fix the pre-processing into the Media Library. I will implement it later today and report back :)

    Any idea why the grid RTE isn't obeying the editor settings? Apparently it's fixed in this issue, but it isn't working for me:   http://issues.umbraco.org/issue/U4-4212

  • schlubadub 102 posts 617 karma points
    Apr 15, 2015 @ 09:59
    schlubadub
    105

    Brilliant! That pre-processing code works like a charm. I had to work out the right libraries to use to get it to work, so the code is below.

    Basic process:

    * Create an empty class file (I created a folder called "Events" and then a class called "UmbracoEvents" with filename UmbracoEvents.cs, but you can call it whatever you like)

    * Put in the following code (Note: 1920 pixels is hard-coded, change to your own size or perhaps change to get from a web.config setting)

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Web;
    using Umbraco.Core;
    using Umbraco.Core.Configuration;
    using Umbraco.Core.Configuration.UmbracoSettings;
    using Umbraco.Core.IO;
    using Umbraco.Core.Models;
    using Umbraco.Core.Services;
    using ImageProcessor;
    using ImageProcessor.Imaging;
    
    namespace Umbraco.Extensions.EventHandlers
    {
        public class UmbracoEvents : ApplicationEventHandler
        {
            protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
            {
                // Tap into the Saving event
                MediaService.Saving += (sender, args) =>
                {
                    MediaFileSystem mediaFileSystem = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
                    IContentSection contentSection = UmbracoConfig.For.UmbracoSettings().Content;
                    IEnumerable<string> supportedTypes = contentSection.ImageFileTypes.ToList();
    
                    foreach (IMedia media in args.SavedEntities)
                    {
                        if (media.HasProperty("umbracoFile"))
                        {
                            //Make sure it's an image.
                            string path = media.GetValue<string>("umbracoFile");
                            string extension = Path.GetExtension(path).Substring(1);
                            if (supportedTypes.InvariantContains(extension))
                            {
                                //Resize the image to 1920px wide, height is driven by the aspect ratio of the image.
                                string fullPath = mediaFileSystem.GetFullPath(path);
                                using (ImageFactory imageFactory = new ImageFactory(true))
                                {
                                    ResizeLayer layer = new ResizeLayer(new Size(1920, 0), ResizeMode.Max)
                                    {
                                        Upscale = false
                                    };
    
                                    imageFactory.Load(fullPath)
                                                            .Resize(layer)
                                                            .Save(fullPath);
                                }
                            }
                        }
                    }
                };
            }
        }
    }

    That's it! There's nothing else to do, as Umbraco auto-magically starts to use it.

     

    Now if I can just figure out why the RTE isn't using the specified max image size I can put this topic to rest!

  • Jan Skovgaard 11280 posts 23678 karma points MVP 10x admin c-trib
    Apr 15, 2015 @ 15:56
    Jan Skovgaard
    0

    Hi Hi Schlubadub

    Wow, thanks for sharing the above code - I'm sure others will benefit from it too :)

    Regarding the issue I'm not sure - What version of Umbraco 7 are you using? Is it 7.2.x? It might be worth re-opening it by adding a new issue and referencing the old one if you keep seeing it.

    /Jan

  • jonok 297 posts 657 karma points
    Apr 15, 2015 @ 23:18
    jonok
    0

    This looks great, but is it going to run the resize code every time an image is saved? I'm thinking you'd only want to run it on the first time the image is saved? (And then perhaps check if the width is greater than 1920 before resizing again?)

  • schlubadub 102 posts 617 karma points
    Apr 16, 2015 @ 11:30
    schlubadub
    1

    @jonok it looks like it does run the through the process every time it's saved... even just changing the image name will trigger it. I don't really see it as an issue though, as images would rarely need to be renamed and if they are changing the image file itself then it does need to be processed to ensure it's not too large.

    It would be a good idea to check if the size is already less than 1920, but I suspect the ImageProcessor ImageFactory code would handle that internally... in fact, if I dig through the ImageProcessor source code (here) I come across the following line, which means that the original image is just returned unchanged:

    // Exit if upscaling is not allowed.
    if ((width > sourceWidth || height > sourceHeight) && upscale == false && resizeMode != ResizeMode.Stretch)
    {
     return (Bitmap)source;
    }
  • jonok 297 posts 657 karma points
    Apr 16, 2015 @ 12:56
    jonok
    1

    Nice work, they're way ahead of me :)

  • schlubadub 102 posts 617 karma points
    Apr 21, 2015 @ 05:32
    schlubadub
    0

    Hi Jan,

    Yes, this is with 7.2.4 - I'll have another look at the RTE issue later as I'm swamped with work at the moment.

    BTW I hope you don't mind if I mark my own reply as the answer - your link provided me all the answers, but my reply has the actual solution that might help someone else.

  • Jan Skovgaard 11280 posts 23678 karma points MVP 10x admin c-trib
    Apr 21, 2015 @ 21:59
    Jan Skovgaard
    1

    Hi Schlubadub

    I don't mind that - Your reply contains the solution and is what people should be able to jump to. That's what matters :) and H5YR for sharing.

    /Jan

  • jonok 297 posts 657 karma points
    Apr 26, 2015 @ 03:10
    jonok
    0

    This is working great until I add the image cropper property to an image. Then it just seems to hang after pressing 'save' on a media item. Is anybody else seeing this too?

     

    Or is there a way to just restrict this code to run when a media item has been created/uploaded?

  • schlubadub 102 posts 617 karma points
    Apr 28, 2015 @ 07:53
    schlubadub
    0

    @jonok - it works fine when I use an ImageCropper as a Property Type. I'm not able to add an ImageCropper as a Media Type (I tried, but it refuses to appear in the child nodes) so I can't test this at my end.

    Perhaps you can check the media type when saving and skip the process if it's a ImageCropper instead of an Image? (I'm not sure how to do this though!)

  • jonok 297 posts 657 karma points
    Apr 28, 2015 @ 08:08
    jonok
    0

    I'm using the image cropper in place of the upload property - is this how you are using the image cropper?

  • schlubadub 102 posts 617 karma points
    Apr 28, 2015 @ 09:03
    schlubadub
    0

    Okay, I tried doing it that way and it does bomb out. If I keep the original Upload property but create a new ImageCropper field underneath it still works... so yeah, something weird is going on! I'm not sure what the solution is, other than avoiding using the ImageCropper as the default for all the images, or working out how to bypass it in that Save function...

  • Dirk Seefeld 126 posts 665 karma points
    Apr 28, 2015 @ 13:16
    Dirk Seefeld
    5

    Hi all,

    I see two major issues in schlubadub's code example.

    First: You should check the path against empty string, because it will be empty ie. when you create an Image node directly via context menu or in case you later remove files etc.

    Second: The Image Cropper data type stores a json object for all its settings. The path is only one of these and stored in the src parameter.

    Btw. I think you should encapsulate the resizeing in a try / catch block and log any exception.

    Here are some quick additions to the code:

    using Umbraco.Core.Logging;
    ...

    string
     path = media.GetValue<string>("umbracoFile"); if (String.IsNullOrEmpty(path))     return;//in case you create an image node directly without upload or later remove file - at least it is always a good idea to make event handlers rock solid! if (path.Contains("{")) {     //this might happen after changing the data type of umbracoFile from Image Cropper back to Upload. Not a good idea at all ;-)     var cropper = Json.Decode(path);     if (!String.IsNullOrEmpty(cropper.Src))     {         path = cropper.Src;     }     else     {         return;     } } try {     //omitted for brevity } catch (Exception ex) {     //for all unexpected errors we get a hint in the log file.     LogHelper.Error<MyMediaEvents>(         String.Format(             "Could not resize image. Path: {0}",             path)         , ex); }

    I would have posted a complete solution, but run out of time :(

    What also has to be done is updating the other properties: Size, Width and Height 

    And it would be nice to force Umbraco to show an error message in case of an exception. However I could not figure out yet, how to do that properly.

    Yours,
    Dirk

  • jonok 297 posts 657 karma points
    May 01, 2015 @ 01:51
    jonok
    0

    Great work Dirk - that solves the cropper problem. Thanks very much.

  • schlubadub 102 posts 617 karma points
    May 12, 2015 @ 10:19
    schlubadub
    0

    @Dirk - all good points! In my defence, I didn't write the code but only got it running from the 3rd party link and shared it :) Thanks for posting your fixes!

    If anyone comes across this thread, you will also have to add "using System.Web.Helpers;" for Json.Decode

  • James Jackson-South 489 posts 1747 karma points c-trib
    May 13, 2015 @ 16:42
    James Jackson-South
    2

    #H5YR all round guys! I love seeing this kind of interaction based on my work.

  • schlubadub 102 posts 617 karma points
    May 24, 2015 @ 13:14
    schlubadub
    0

    Thanks James, all credit to you!

Please Sign in or register to post replies

Write your reply to:

Draft