Copied to clipboard

Flag this post as spam?

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


  • aerksn 7 posts 78 karma points
    Jun 17, 2022 @ 09:10
    aerksn
    0

    Umbraco 10 WebP file much larger than png

    Just updated to version 10 and tried the webp encoding Isn't webp suppose to be smaller, or not atleast 8-10x larger ?

    enter image description here

    https://appnitecloud.azurewebsites.net/media/c1cn1kpg/gympartnervit.png?format=webp

    webp = 125KB

    https://appnitecloud.azurewebsites.net/media/c1cn1kpg/gympartnervit.png?format=png

    png = 19KB

  • Dennis 61 posts 309 karma points
    Jun 17, 2022 @ 13:42
    Dennis
    0

    Hi aerksn,

    On first thought, yeah, usually images encoded as webp are supposed to be smaller. Looking at your image though, I see it has very few different colours and if I remember correctly, png is already quite optimised if there are few different colours. I'd say: try the same thing with a photograph of the same dimensions or try it with a jpeg version of the same image and see if webp is still larger than the original image.

    kind regards, Dennis

  • aerksn 7 posts 78 karma points
    Jun 17, 2022 @ 20:26
    aerksn
    0

    jpeg and all other formats works fine, except all pngs. Don't know if i ever had issue with that before.

    Here the exact same image on .framework (umbraco 8) https://www.gympartner.nu/media/nw3dmqcc/gympartnervit.png?format=webp

    I did a workaround for now on it, (thanks @Kamil for the tip)

    services.AddImageSharp(options =>
            {
                options.OnParseCommandsAsync = c =>
                {
                    bool wantsformat = c.Commands.TryGetValue("format", out string value);                   
    
                    if (wantsformat)
                    {
                        bool isPng = c.Context.Request.Path.Value.Contains(".png");
    
                        if (isPng && value == "webp")
                            c.Commands.Remove("format");
                    }
                    return Task.CompletedTask;
                };
            });
    
  • Kamil 6 posts 75 karma points
    Jun 18, 2022 @ 05:56
    Kamil
    1

    aerksn,

    I think in general you're losing performance with this as I think your logo is a bit of a special case. The WebP optimization for other png images should still be (very) helpful.

    In your code you're removing format - so you're "reverting" developer intent (I assume you're appending the ?format= to every image src?)

    How about doing this in another way. You can implement for example a middleware:

    public class WebPMiddleware
    {
        private readonly RequestDelegate _next;
    
        public WebPMiddleware(RequestDelegate next)
        {
            _next = next;
    
        }
    
        public async Task Invoke(HttpContext httpContext)
        {
            if (IsImageRequest(httpContext) &&
                httpContext.Request.GetTypedHeaders()?.Accept != null 
                && httpContext.Request.GetTypedHeaders().Accept.Any(aValue => aValue.MediaType.Value == "image/webp"))
            {
                var updatedQueryString = GetUpdatedQueryString(httpContext);
    
                var qb1 = new QueryBuilder(updatedQueryString);
    
                httpContext.Request.QueryString = qb1.ToQueryString();
            }
    
            await _next(httpContext);
        }
    
        private bool IsImageRequest(HttpContext httpContext)
        {
            var path = httpContext.Request.Path.ToString();
    
            return path.EndsWith("png") || path.EndsWith("jpg") || path.EndsWith("jpeg");
        }
    
        private List<KeyValuePair<string, string>> GetUpdatedQueryString(HttpContext httpContext)
        {
            var queryitems = httpContext.Request.Query.SelectMany(x => x.Value, (col, value) => new KeyValuePair<string, string>(col.Key, value)).ToList();
            var queryParameters = new List<KeyValuePair<string, string>>();
    
            foreach (var item in queryitems)
            {
                var value = item.Value;
    
                if (item.Key == "format")
                {
                    value = "webp";
                }
    
                var newQueryParameter = new KeyValuePair<string, string>(item.Key, value);
    
                queryParameters.Add(newQueryParameter);
            }
    
            if (!queryParameters.Any())
            {
                queryParameters.Add(new KeyValuePair<string, string>("format", "webp"));
            }
    
            return queryParameters;
        }
    }
    public static class WebPMiddlewareExtensions
    {
        public static IApplicationBuilder UseWebP(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<WebPMiddleware>();
        }
    }
    

    use it:

            app.UseWebP();
    
            app.UseImageSharp();
    

    and then transform your code to something else:

         services.AddImageSharp(options =>
        {
            options.OnParseCommandsAsync = c =>
            {
                bool doesntWantFormat = c.Commands.TryGetValue("noformat", out string value);                   
    
                if (doesntWantFormat)
                {
                        c.Commands.Remove("format");
                }
                return Task.CompletedTask;
            };
        });
    

    and then WebP works by default for all images except the ones you want to have it disabled, like this:

    https://appnitecloud.azurewebsites.net/media/c1cn1kpg/gympartnervit.png?noformat=true
    

    I tested the above code and it works - just a random saturday idea :)

  • Matthew 10 posts 85 karma points
    Jun 18, 2022 @ 15:36
    Matthew
    0

    Hey, this solution works great. Thanks for sharing. One thing I've found however with both solutions is that neither works when you enable CDN URL with the Azure Blob Storage. Any ideas on how to get the WEBP functionality working when utilizing the CDN URL as well?

  • Kamil 6 posts 75 karma points
    Jun 18, 2022 @ 15:47
    Kamil
    0

    I'm glad you like it!

    I'm not utilising CDN in my project so unfortunately I can't play with it without doing some more setting up for which I don't have time today but I have an idea.

    The first thing that came into my mind is that you might need to implement custom image provider - more in the links:

    https://our.umbraco.com/forum/using-umbraco-and-getting-started/108123-umbraco9-local-and-remote-images

    https://github.com/SixLabors/ImageSharp.Web/discussions/167

    Let us know how you get on!

  • aerksn 7 posts 78 karma points
    Jun 20, 2022 @ 21:18
    aerksn
    1

    Thanks for the reply and thanks to all of you for your tips. I've tried and tried different approaches to get to a good solution that works for me.

    After some digging in the encoder i found "Image.PixelType.BitsPerPixel" and found a correlation between png and jpegs.

    The jpges are 24px and pngs are 32px, in that way i could sepparate them. And depending on that use different compression types. Which made it all work. Haha, 🙌

    So now i'm getting the images in correct size.

    Idon't auctually know what i'm doing but it works... haha

         services.AddImageSharp(options =>
            {
                options.OnBeforeSaveAsync = c =>
                {
                    if(c.Encoder.GetType().Name == "WebpEncoder"){
                        c.Encoder = new WebpEncoder()
                        {
                            FileFormat = c.Image.PixelType.BitsPerPixel < 30 ? WebpFileFormatType.Lossy : WebpFileFormatType.Lossless,                          
                        };
                    }                 
                    return Task.CompletedTask;
                };
            });
    

    (btw you can edit all properties in the encoder object as well if you want to tweak it even more)

  • Arjan H. 180 posts 337 karma points c-trib
    Jul 19, 2022 @ 15:37
    Arjan H.
    0

    I believe the 32 bits per pixel has to do with transparency: an additional 8 bits for the alpha channel. So I guess it's a good way to determine if a PNG contains transparency. However, I'm not sure if using Lossless WebP encoding for 32 bpp images will always result in a smaller image than the original PNG. It may depend on the image, see the following discussion:

    https://github.com/SixLabors/ImageSharp/discussions/1957

    Have you experienced any issues with your code? Or did all the JPG and PNG images that you run through this code have a smaller WebP encoded image?

  • Matthew 10 posts 85 karma points
    Jun 17, 2022 @ 14:32
    Matthew
    0

    Hey there, just curious, how do you enable webp encoding for images in v10? Just adding the ?format=webp still shows encoding as the original format in the network tab for me.

  • Kamil 6 posts 75 karma points
    Jun 17, 2022 @ 15:23
    Kamil
    101

    Matthew, I came across same problem despite hearing that it should happen OOTB.

    I've enabled the ImageSharp2 manually, in Startup.cs: in ConfigureServices:

            services.AddImageSharp();
    

    in Configure:

            app.UseImageSharp();
    

    PS If these methods aren't found there's a nuget SixLabors.ImageSharp in v2.1.2

    PS2 Remember to add the above line before UseStaticFiles!

  • Matthew 10 posts 85 karma points
    Jun 17, 2022 @ 15:58
    Matthew
    2

    Thank you for the tip, it looks like that worked!

  • Aaron 39 posts 321 karma points c-trib
    Jun 22, 2022 @ 16:17
    Aaron
    0

    Hey Kamil!

    I've tried your code in V10, however it doesn't seem to work.

    Nothing inside of /Media hits your middleware, I presume this is due to the way Umbraco is now registering the static assets in program.cs rather than startup.cs?

Please Sign in or register to post replies

Write your reply to:

Draft