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.
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:
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?
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:
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
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.
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?
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 ?
https://appnitecloud.azurewebsites.net/media/c1cn1kpg/gympartnervit.png?format=webp
webp = 125KB
https://appnitecloud.azurewebsites.net/media/c1cn1kpg/gympartnervit.png?format=png
png = 19KB
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
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)
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:
use it:
and then transform your code to something else:
and then WebP works by default for all images except the ones you want to have it disabled, like this:
I tested the above code and it works - just a random saturday idea :)
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?
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!
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
(btw you can edit all properties in the encoder object as well if you want to tweak it even more)
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.
Matthew, I came across same problem despite hearing that it should happen OOTB.
I've enabled the ImageSharp2 manually, in Startup.cs: in ConfigureServices:
in Configure:
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!
Thank you for the tip, it looks like that worked!
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?
is working on a reply...