diff --git a/README.md b/README.md
index 7dfd984c..e9607da9 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,11 @@ Dianoga supports:
* PNGs (via PNGOptimizer - lossless / pngquant - lossy)
* SVGs (via SVGO - lossless, and automatic gzipping of SVG media responses)
* WebP (via cwebp - lossless or lossy)
+* Avif (via avifenc - lossless or lossy)
+* JPEG XL (via cjxl - lossless or lossy)
* Auto convert JPEG/PNG/GIF to WebP based on browser support
+* Auto convert JPEG/PNG to Avif based on browser support
+* Auto convert JPEG/PNG/GIF to JPEG XL (jxl) based on browser support
Additional format support is possible to add via new processors in the `dianogaOptimize` pipeline.
@@ -63,30 +67,72 @@ To perform a manual installation:
If you are enabling the SVGO optimiser, you'll also need the [Dianoga.svgtools](https://www.nuget.org/packages/Dianoga.svgtools) NuGet package.
This is simply a prepackaged compiled version of SVGO called SVGOP from [here](https://github.com/twardoch/svgop).
-## WebP feature
+## Next-gen Formats Support
-WebP is is an image format employing both lossy and lossless compression. It is currently developed by Google, based on technology acquired with the purchase of On2 Technologies. WebP file size is [25%-34% smaller compared to JPEG file size](https://developers.google.com/speed/webp/docs/webp_study) and [26% smaller for PNG](https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study). [All evergreen browsers except Safari currently support WebP](https://caniuse.com/#feat=webp). By default WebP optimization is disabled since you need to do some due diligence around reviewing configs, how it works, and importantly if you are using a CDN you need to do some extra steps.
+Next-gen images use formats with superior compression and quality characteristics compared to their GIF, JPEG, and PNG ancestors. These image formats support advanced features designed to take up less data while maintaining a high quality level, making them perfect for web use.
-### How WebP optimization works:
-Browser sends request to server to get image. If browser supports WebP image format then it sends "image/webp" value in Accept header. It is possible to detect this header on server and return WebP image to browser instead of JPEG or PNG. If browser doesn't support WebP then other image optimizers are executed if they are enabled.
+### How Next-gen Formats Optimization Works:
-### How to enable WebP support:
-1. Enable `Dianoga.WebP.config.disabled` config and adjust any parameters if you require lossless or higher quality than the default
-2. Open web.config and change line
+Browser sends request to server to get image. It sends list of accepted image formats in the `Accept` header, e.g. it can be `image/avif,image/webp,image/apng,image/*,*/*;q=0.8`. Presence of `image/webp` means that this browser supports `WebP` image format. Absense of `image/jxl` means that this browser does not support `JPEG XL` format. It is possible to check this header on server side and return `WebP` format image to browser instead of `JPEG`, `PNG` or `GIF`. If browser doesn't support any next-gen formats then other image optimizers are executed if they are enabled.
+
+### How to Enable Next-gen Formats Support:
+
+1. Open web.config and change line
``
to
-``
+``
OR if you use SXA
-``
+``
OR if you have a custom `MediaRequestHandler` then you need to make some changes - see `MediaRequestHandler.cs`
-3. If you run Sitecore under CDN: carefully review and enable `Dianoga.WebP.CDN.config.disabled`, and disable `Dianoga.Strategy.GetMediaStreamSync.config`.
+2. If you run Sitecore under CDN: review and enable `Dianoga.NextGenFormats.CDN.config.disabled`. It will add `?extension=` query parameter to all images present on your pages.
+
+3. Enable any next-gen formats configuration files that you want. e.g.: `z.01.Dianoga.NextGenFormats.WebP.config.disabled`, `z.02.Dianoga.NextGenFormats.Avif.config.disabled`, `z.03.Dianoga.NextGenFormats.Jxl.config.disabled`
+
+4. Review files that you have enabled and adjust any parameters if you require lossless or higher quality than the default
+
+5. Adjust order of next-gen formats configuration files.
+
+WebP, Avif and JPEG XL formats are not convertable to each other. Dianoga works with file stream and сonsistently converts file stream using optimizers.
+e.g. JPEG > mozjpeg > Avif. Once stream is converted to one next-gen format it could not be easily reconverted to another format, e.g. Avif <=> WebP, because current encoders doesn't support it.
+
+Configuration files should be applied in **reversed** priority order. The first format should be applied in last confiration file.
+
+E.g. We want to support all JPEG XL, Avif and WebP in next priority 1. JPEG XL 2. Avif 3. WebP. If browser supports JPEG XL then try to use it. If browser doesn't support JPEG XL then check if browser support Avif and try to use it. If browser doesn't support both JPEG XL and Avif then check if browser supports WebP and try to use it.
+
+Then next-gen configuration file names should have prefixes to put files in the proper order: **z.01**.Dianoga.NextGenFormats.WebP.config.disabled, **z.02**.Dianoga.NextGenFormats.Avif.config.disabled, **z.03**.Dianoga.NextGenFormats.Jxl.config.disabled
+
+### Next-gen formats list
+
+#### WebP
+
+WebP is is an image format employing both lossy and lossless compression. It is currently developed by Google, based on technology acquired with the purchase of On2 Technologies. WebP file size is [25%-34% smaller compared to JPEG file size](https://developers.google.com/speed/webp/docs/webp_study) and [26% smaller for PNG](https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study). [All evergreen browsers except Safari currently support WebP](https://caniuse.com/#feat=webp).
+
+By default WebP optimization is disabled since you need to do some due diligence around reviewing configs, how it works, and importantly if you are using a CDN you need to do some extra steps.
+
+If you want to enable usage of `WebP` format, please rename `z.01.Dianoga.NextGenFormats.WebP.config.disabled` to `z.01.Dianoga.NextGenFormats.WebP.config`
+
+#### Avif
+
+Avif is a modern image format based on the AV1 video format. AVIF generally has better compression than WebP, JPEG, PNG and GIF and is designed to supersede them. AVIF competes with JPEG XL which has worse support, similar compression quality and is generally seen as more feature-rich than AVIF. [Avif is supported by Chrome and Firefox browsers](https://caniuse.com/#feat=avif).
+
+By default Avif optimization is disabled since you need to do some due diligence around reviewing configs, how it works, and importantly if you are using a CDN you need to do some extra steps.
+
+If you want to enable usage of `Avif` format, please rename `z.02.Dianoga.NextGenFormats.Avif.config.disabled` to `z.02.Dianoga.NextGenFormats.Avif.config`
+
+#### JPEG XL
+
+JPEG XL is a modern image format optimized for web environments. JPEG XL generally has better compression than WebP, JPEG, PNG and GIF and is designed to supersede them. JPEG XL competes with AVIF which has better support, similar compression quality but fewer features overall. JPEG XL is not supported yet by modern browsers. [But support could be enabled via flags in Chrome, Firefox, Opera and Edge](https://caniuse.com/?search=jpeg%20xl).
+
+By default JPEG XL optimization is disabled since you need to do some due diligence around reviewing configs, how it works, and importantly if you are using a CDN you need to do some extra steps.
+
+If you want to enable usage of `JPEG XL` format, please rename `z.03.Dianoga.NextGenFormats.Jxl.config.disabled` to `z.02.Dianoga.NextGenFormats.Jxl.config`
## Upgrade
diff --git a/src/Dianoga.Tests/NextGenFormats/HelpersTests.cs b/src/Dianoga.Tests/NextGenFormats/HelpersTests.cs
new file mode 100644
index 00000000..70a22bf2
--- /dev/null
+++ b/src/Dianoga.Tests/NextGenFormats/HelpersTests.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Web;
+using Dianoga.NextGenFormats;
+using FluentAssertions;
+using Moq;
+using Xunit;
+
+namespace Dianoga.Tests.NextGenFormats
+{
+ public class HelpersTests
+ {
+ [Fact]
+ public void GetSupportedFormats_ShouldCallAndReturnValueFromdianogaGetSupportedFormatsPipeline()
+ {
+ //Arrange
+ var context = new Mock();
+ var request = new Mock();
+ var acceptTypes = new[] {"image/webp"};
+ request.SetupGet(r => r.AcceptTypes).Returns(acceptTypes);
+ context.Setup(ctx => ctx.Request).Returns(request.Object);
+ var helpers = new Helpers();
+ var pipelineHelpers = new Mock();
+ pipelineHelpers.Setup(h => h.RunDianogaGetSupportedFormatsPipeline(It.IsAny())).Returns("webp").Verifiable();
+ helpers.PipelineHelpers = pipelineHelpers.Object;
+
+ //Act
+ var result = helpers.GetSupportedFormats(context.Object);
+
+ //Assert
+ result.Should().Be("webp", "");
+ pipelineHelpers.Verify(m=>m.RunDianogaGetSupportedFormatsPipeline(acceptTypes), Times.Once());
+ }
+
+ [Fact]
+ public void GetSupportedFormats_ShouldNotCallDianogaGetSupportedFormatsPipeline_WhenNoAcceptTypes()
+ {
+ //Arrange
+ var context = new Mock();
+ var request = new Mock();
+ context.Setup(ctx => ctx.Request).Returns(request.Object);
+ var helpers = new Helpers();
+ var pipelineHelpers = new Mock();
+ helpers.PipelineHelpers = pipelineHelpers.Object;
+
+ //Act
+ var result = helpers.GetSupportedFormats(context.Object);
+
+ //Assert
+ result.Should().Be(String.Empty, "");
+ pipelineHelpers.Verify(m => m.RunDianogaGetSupportedFormatsPipeline(It.IsAny()), Times.Never);
+ }
+
+ [Fact]
+ public void GetCustomOptions_ShouldTakeValueFromQueryString_WhenExtensionQueryStringIsPresent()
+ {
+ //Arrange
+ var context = new Mock();
+ var request = new Mock();
+ context.Setup(ctx => ctx.Request).Returns(request.Object);
+ var acceptTypes = new[] { "image/webp" };
+ request.SetupGet(r => r.AcceptTypes).Returns(acceptTypes);
+ var queryString = new NameValueCollection();
+ queryString.Add("extension", "webp,avif");
+ request.SetupGet(r => r.QueryString).Returns(queryString);
+ var helpers = new Helpers();
+ var pipelineHelpers = new Mock();
+ helpers.PipelineHelpers = pipelineHelpers.Object;
+
+ //Act
+ var result = helpers.GetCustomOptions(context.Object);
+
+ //Assert
+ result.Should().Be("webp,avif", "");
+ pipelineHelpers.Verify(m => m.RunDianogaGetSupportedFormatsPipeline(It.IsAny()), Times.Never);
+ }
+
+ [Fact]
+ public void GetCustomOptions_ShouldTakeValueFromFromAcceptTypes_WhenExtensionQueryStringIsEmpty()
+ {
+ //Arrange
+ var context = new Mock();
+ var request = new Mock();
+ context.Setup(ctx => ctx.Request).Returns(request.Object);
+ var acceptTypes = new[] { "image/webp", "image/avif" };
+ request.SetupGet(r => r.AcceptTypes).Returns(acceptTypes);
+ var queryString = new NameValueCollection();
+ queryString.Add("extension", "");
+ request.SetupGet(r => r.QueryString).Returns(queryString);
+ var helpers = new Helpers();
+ var pipelineHelpers = new Mock();
+ pipelineHelpers.Setup(h => h.RunDianogaGetSupportedFormatsPipeline(It.IsAny())).Returns("webp,avif").Verifiable();
+ helpers.PipelineHelpers = pipelineHelpers.Object;
+
+ //Act
+ var result = helpers.GetCustomOptions(context.Object);
+
+ //Assert
+ result.Should().Be("webp,avif", "");
+ pipelineHelpers.Verify(m => m.RunDianogaGetSupportedFormatsPipeline(It.IsAny()), Times.Once);
+ }
+ }
+}
diff --git a/src/Dianoga.Tests/NextGenFormats/Pipelines/DianogaGetSupportedFormats/CheckSupport.cs b/src/Dianoga.Tests/NextGenFormats/Pipelines/DianogaGetSupportedFormats/CheckSupport.cs
new file mode 100644
index 00000000..8cd0384c
--- /dev/null
+++ b/src/Dianoga.Tests/NextGenFormats/Pipelines/DianogaGetSupportedFormats/CheckSupport.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Specialized;
+using System.Web;
+using Dianoga.NextGenFormats;
+using Dianoga.NextGenFormats.Pipelines.DianogaGetSupportedFormats;
+using Moq;
+using FluentAssertions;
+using Xunit;
+
+namespace Dianoga.Tests.NextGenFormats
+{
+ public class CheckSupportTests
+ {
+ [Fact]
+ public void ShouldFindFormatSupportInAccepts_WhenItIsPresent()
+ {
+ //Arrange
+ var args = new SupportedFormatsArgs()
+ {
+ Input = "image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
+ Prefix = "image/"
+ };
+
+ var CheckSupport = new CheckSupport()
+ {
+ Extension = "webp"
+ };
+
+ //Act
+ CheckSupport.Process(args);
+
+ //Assert
+ args.Extensions.Should().HaveCount(1);
+ args.Extensions.Should().Contain("webp");
+ }
+
+ [Fact]
+ public void ShouldNotFindFormatSupportInAccepts_WhenItIsAbsent()
+ {
+ //Arrange
+ var args = new SupportedFormatsArgs()
+ {
+ Input = "image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
+ Prefix = "image/"
+ };
+
+ var CheckSupport = new CheckSupport()
+ {
+ Extension = "jxl"
+ };
+
+ //Act
+ CheckSupport.Process(args);
+
+ //Assert
+ args.Extensions.Should().HaveCount(0);
+ }
+ }
+}
diff --git a/src/Dianoga.Tests/Optimizers/Pipelines/DianogaAvif/AvifOptimizerTests.cs b/src/Dianoga.Tests/Optimizers/Pipelines/DianogaAvif/AvifOptimizerTests.cs
new file mode 100644
index 00000000..7f3a4c07
--- /dev/null
+++ b/src/Dianoga.Tests/Optimizers/Pipelines/DianogaAvif/AvifOptimizerTests.cs
@@ -0,0 +1,129 @@
+using System.Diagnostics;
+using System.IO;
+using Dianoga.Optimizers;
+using Dianoga.Optimizers.Pipelines.DianogaAvif;
+using FluentAssertions;
+using FluentAssertions.Common;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Dianoga.Tests.Optimizers.Pipelines.DianogaAvif
+{
+ public class AvifOptimizerTests
+ {
+ ITestOutputHelper output;
+ public AvifOptimizerTests(ITestOutputHelper output)
+ {
+ this.output = output;
+ }
+
+ [Fact]
+ public void ShouldReturnOriginalStreamWhenOptimizedImageSizeIsGreater()
+ {
+ Test(@"TestImages\small.jpg",
+ @"..\..\..\..\Dianoga\Dianoga Tools\avif\avifenc.exe",
+ "-s 10 -l", out var args, out var startingSize);
+ args.Stream.Length.Should().Be(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeFalse();
+ }
+
+ [Fact]
+ public void ShouldSquishLosslessSmallPng()
+ {
+ Test(@"TestImages\small.png",
+ @"..\..\..\..\Dianoga\Dianoga Tools\avif\avifenc.exe",
+ "-s 10 -l", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLosslessLargePngButBeTooBig()
+ {
+ Test(@"TestImages\large.png",
+ @"..\..\..\..\Dianoga\Dianoga Tools\avif\avifenc.exe",
+ "-s 10 -l", out var args, out var startingSize);
+ args.Stream.Length.Should().Be(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeFalse();
+ }
+
+ [Fact]
+ public void ShouldSquishLossySmallJpegDefaults()
+ {
+ Test(@"TestImages\small.jpg",
+ @"..\..\..\..\Dianoga\Dianoga Tools\avif\avifenc.exe",
+ "-s 10", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLossyLargeJpegDefaults()
+ {
+ Test(@"TestImages\large.jpg",
+ @"..\..\..\..\Dianoga\Dianoga Tools\avif\avifenc.exe",
+ "-s 10", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldNotSquishCorruptedJpegLossy()
+ {
+ Test(@"TestImages\corrupted.jpg",
+ @"..\..\..\..\Dianoga\Dianoga Tools\avif\avifenc.exe",
+ "-s 10", out var args, out var startingSize);
+ args.Stream.Length.Should().IsSameOrEqualTo(startingSize);
+ args.IsOptimized.Should().BeFalse();
+ }
+
+ [Fact]
+ public void ShouldSquishLossySmallPngDefaults()
+ {
+ Test(@"TestImages\small.png",
+ @"..\..\..\..\Dianoga\Dianoga Tools\avif\avifenc.exe",
+ "-s 10", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLossyLargePngDefaults()
+ {
+ Test(@"TestImages\large.png",
+ @"..\..\..\..\Dianoga\Dianoga Tools\avif\avifenc.exe",
+ "-s 10", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ private void Test(string imagePath, string exePath, string exeArgs, out OptimizerArgs argsOut, out long startingSize)
+ {
+ var inputStream = new MemoryStream();
+
+ using (var testJpeg = File.OpenRead(imagePath))
+ {
+ testJpeg.CopyTo(inputStream);
+ }
+
+ var sut = new AvifOptimizer();
+ sut.ExePath = exePath;
+ sut.AdditionalToolArguments = exeArgs;
+
+ var opts = new Sitecore.Resources.Media.MediaOptions();
+ opts.CustomOptions["extension"] = "avif";
+ var args = new OptimizerArgs(inputStream, opts, imagePath);
+
+ startingSize = args.Stream.Length;
+
+ var stopwatch = new Stopwatch();
+ stopwatch.Start();
+ sut.Process(args);
+ stopwatch.Stop();
+ output.WriteLine($"Time: {stopwatch.ElapsedMilliseconds}ms");
+
+ argsOut = args;
+ }
+
+ }
+}
diff --git a/src/Dianoga.Tests/Optimizers/Pipelines/DianogaJxl/JxlOptimizerTests.cs b/src/Dianoga.Tests/Optimizers/Pipelines/DianogaJxl/JxlOptimizerTests.cs
new file mode 100644
index 00000000..aec330ff
--- /dev/null
+++ b/src/Dianoga.Tests/Optimizers/Pipelines/DianogaJxl/JxlOptimizerTests.cs
@@ -0,0 +1,184 @@
+using System.Diagnostics;
+using System.IO;
+using Dianoga.Optimizers;
+using Dianoga.Optimizers.Pipelines.DianogaJxl;
+using FluentAssertions;
+using FluentAssertions.Common;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Dianoga.Tests.Optimizers.Pipelines.DianogaJxl
+{
+ public class JxlOptimizerTests
+ {
+ ITestOutputHelper output;
+ public JxlOptimizerTests(ITestOutputHelper output)
+ {
+ this.output = output;
+ }
+
+ [Fact]
+ public void ShouldReturnOriginalStreamWhenOptimizedImageSizeIsGreater()
+ {
+ Test(@"TestImages\small.jpg",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-q 100", out var args, out var startingSize);
+ args.Stream.Length.Should().Be(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeFalse();
+ }
+
+ [Fact]
+ public void ShouldSquishLosslessSmallPng()
+ {
+ Test(@"TestImages\small.png",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-q 100 --num_threads 1", out var args, out var startingSize);
+
+ /*
+ num_threads is often required parameter
+ JPEG XL encoder v0.6.1 a205468 [SSE4,Scalar]
+ Failed to choose default num_threads; you can avoid this error by specifying a --num_threads N argument.
+ */
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLosslessLargePng()
+ {
+ Test(@"TestImages\large.png",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-q 100 --num_threads 1", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLossyTestJpeg()
+ {
+ Test(@"TestImages\large.jpg",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-q 90 --num_threads 1", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLossySmallJpegDistance()
+ {
+ Test(@"TestImages\small.jpg",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-d 1 --num_threads 1", out var args, out var startingSize);
+
+ /*
+ -d maxError, --distance=maxError
+ Max. butteraugli distance, lower = higher quality. Range: 0 .. 25.
+ 0.0 = mathematically lossless. Default for already-lossy input (JPEG/GIF).
+ 1.0 = visually lossless. Default for other input.
+ Recommended range: 0.5 .. 3.0.
+ */
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLossyLargeJpegDistance()
+ {
+ Test(@"TestImages\small.jpg",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-d 1 --num_threads 1", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldNotSquishCorruptedJpegLossy()
+ {
+ Test(@"TestImages\corrupted.jpg",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-d 1", out var args, out var startingSize);
+ args.Stream.Length.Should().IsSameOrEqualTo(startingSize);
+ args.IsOptimized.Should().BeFalse();
+ }
+
+ [Fact]
+ public void ShouldSquishLossySmallPngHighAlpha()
+ {
+ Test(@"TestImages\small.png",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-q 90 --num_threads 1", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLossySmallPngDistance()
+ {
+ Test(@"TestImages\small.png",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-d 1 --num_threads 1", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLossyLargePngDistance()
+ {
+ Test(@"TestImages\large.png",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-d 1 --num_threads 1", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLossyTestGif()
+ {
+ Test(@"TestImages\small.gif",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-q 90 --num_threads 1", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ [Fact]
+ public void ShouldSquishLosslessTestGif()
+ {
+ Test(@"TestImages\small.gif",
+ @"..\..\..\..\Dianoga\Dianoga Tools\jxl\cjxl.exe",
+ "-q 80 --num_threads 1", out var args, out var startingSize);
+ args.Stream.Length.Should().BeLessThan(startingSize).And.BeGreaterThan(0);
+ args.IsOptimized.Should().BeTrue();
+ }
+
+ private void Test(string imagePath, string exePath, string exeArgs, out OptimizerArgs argsOut, out long startingSize)
+ {
+ var inputStream = new MemoryStream();
+
+ using (var inputFileStream = File.OpenRead(imagePath))
+ {
+ inputFileStream.CopyTo(inputStream);
+ }
+
+ var sut = new JxlOptimizer
+ {
+ ExePath = exePath,
+ AdditionalToolArguments = exeArgs
+ };
+
+ var opts = new Sitecore.Resources.Media.MediaOptions();
+ opts.CustomOptions["extension"] = "jxl";
+ var args = new OptimizerArgs(inputStream, opts, imagePath);
+
+ startingSize = args.Stream.Length;
+
+ var stopwatch = new Stopwatch();
+ stopwatch.Start();
+ sut.Process(args);
+ stopwatch.Stop();
+ output.WriteLine($"Time: {stopwatch.ElapsedMilliseconds}ms");
+
+ argsOut = args;
+ }
+ }
+}
diff --git a/src/Dianoga.Tests/Optimizers/Pipelines/DianogaWebP/WebPOptimizerTests.cs b/src/Dianoga.Tests/Optimizers/Pipelines/DianogaWebP/WebPOptimizerTests.cs
index f9be30b9..1c93fbf4 100644
--- a/src/Dianoga.Tests/Optimizers/Pipelines/DianogaWebP/WebPOptimizerTests.cs
+++ b/src/Dianoga.Tests/Optimizers/Pipelines/DianogaWebP/WebPOptimizerTests.cs
@@ -141,14 +141,16 @@ private void Test(string imagePath, string exePath, string exeArgs, out Optimize
{
var inputStream = new MemoryStream();
- using (var testJpeg = File.OpenRead(imagePath))
+ using (var inputFileStream = File.OpenRead(imagePath))
{
- testJpeg.CopyTo(inputStream);
+ inputFileStream.CopyTo(inputStream);
}
- var sut = new WebPOptimizer();
- sut.ExePath = exePath;
- sut.AdditionalToolArguments = exeArgs;
+ var sut = new WebPOptimizer
+ {
+ ExePath = exePath,
+ AdditionalToolArguments = exeArgs
+ };
var opts = new Sitecore.Resources.Media.MediaOptions();
opts.CustomOptions["extension"] = "webp";
diff --git a/src/Dianoga/Default Config Files/Dianoga.NextGenFormats.CDN.config.disabled b/src/Dianoga/Default Config Files/Dianoga.NextGenFormats.CDN.config.disabled
new file mode 100644
index 00000000..34beed94
--- /dev/null
+++ b/src/Dianoga/Default Config Files/Dianoga.NextGenFormats.CDN.config.disabled
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Dianoga/Default Config Files/Dianoga.NextGenFormats.config b/src/Dianoga/Default Config Files/Dianoga.NextGenFormats.config
new file mode 100644
index 00000000..00bf62c3
--- /dev/null
+++ b/src/Dianoga/Default Config Files/Dianoga.NextGenFormats.config
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Dianoga/Default Config Files/Dianoga.WebP.CDN.config.disabled b/src/Dianoga/Default Config Files/Dianoga.WebP.CDN.config.disabled
deleted file mode 100644
index 05a3c825..00000000
--- a/src/Dianoga/Default Config Files/Dianoga.WebP.CDN.config.disabled
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Dianoga/Default Config Files/Dianoga.WebP.config.disabled b/src/Dianoga/Default Config Files/z.01.Dianoga.NextGenFormats.WebP.config.disabled
similarity index 63%
rename from src/Dianoga/Default Config Files/Dianoga.WebP.config.disabled
rename to src/Dianoga/Default Config Files/z.01.Dianoga.NextGenFormats.WebP.config.disabled
index 93441a7c..c0a05cea 100644
--- a/src/Dianoga/Default Config Files/Dianoga.WebP.config.disabled
+++ b/src/Dianoga/Default Config Files/z.01.Dianoga.NextGenFormats.WebP.config.disabled
@@ -1,60 +1,63 @@
-
+
+
+
+ webp
+
+
+
+
+
+ webp
+
+
webp
dianogaOptimizeWebP
-
- jpg, jpeg, jfif, jpe
- dianogaOptimizeJpeg
-
-
- png
- dianogaOptimizePng
-
-
- gif
- dianogaOptimizeGif
-
-
/App_Data/Dianoga Tools/libwebp/cwebp.exe
-q 80
+
-
+
/App_Data/Dianoga Tools/libwebp/cwebp.exe
-preset photo -q 80
+
-
+
/App_Data/Dianoga Tools/libwebp/cwebp.exe
-preset icon
+
-
+
/App_Data/Dianoga Tools/libwebp/gif2webp.exe
-q 80 -lossy
true
-
-
@@ -64,16 +67,23 @@
system/media/versioned/image
-
+
webp
150
150
-
+
+
+ image/avif
+ false
+ system/media/unversioned/image
+ system/media/versioned/image
+
+
diff --git a/src/Dianoga/Default Config Files/z.02.Dianoga.NextGenFormats.Avif.config.disabled b/src/Dianoga/Default Config Files/z.02.Dianoga.NextGenFormats.Avif.config.disabled
new file mode 100644
index 00000000..313f9f75
--- /dev/null
+++ b/src/Dianoga/Default Config Files/z.02.Dianoga.NextGenFormats.Avif.config.disabled
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ avif
+
+
+
+
+
+ avif
+
+
+
+
+
+ /App_Data/Dianoga Tools/avif/avifenc.exe
+ -s 10
+
+
+
+
+
+ /App_Data/Dianoga Tools/avif/avifenc.exe
+ -s 10
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Dianoga/Default Config Files/z.03.Dianoga.NextGenFormats.JpegXL.config.disabled b/src/Dianoga/Default Config Files/z.03.Dianoga.NextGenFormats.JpegXL.config.disabled
new file mode 100644
index 00000000..b0c5315e
--- /dev/null
+++ b/src/Dianoga/Default Config Files/z.03.Dianoga.NextGenFormats.JpegXL.config.disabled
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+ jxl
+
+
+
+
+
+ jxl
+
+
+
+
+
+ jxl
+ dianogaOptimizeJxl
+
+
+
+
+
+ /App_Data/Dianoga Tools/jxl/cjxl.exe
+ -q 80 --num_threads 1
+
+
+
+
+
+ /App_Data/Dianoga Tools/jxl/cjxl.exe
+ -q 80 --num_threads 1
+
+
+
+
+
+ /App_Data/Dianoga Tools/jxl/cjxl.exe
+ -q 80 --num_threads 1
+
+
+
+
+
+ /App_Data/Dianoga Tools/jxl/cjxl.exe
+ -q 80 --num_threads 1
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Dianoga/Dianoga Tools/avif/LICENSE.txt b/src/Dianoga/Dianoga Tools/avif/LICENSE.txt
new file mode 100644
index 00000000..e8318ef7
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/avif/LICENSE.txt
@@ -0,0 +1,170 @@
+Copyright 2019 Joe Drago. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------------------------------------------
+
+Files: tests/cJSON.*
+
+Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+------------------------------------------------------------------------------
+
+Files: src/obu.c
+
+Copyright © 2018-2019, VideoLAN and dav1d authors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------------------------------------------
+
+Files: apps/shared/iccjpeg.*
+
+In plain English:
+
+1. We don't promise that this software works. (But if you find any bugs,
+ please let us know!)
+2. You can use this software for whatever you want. You don't have to pay us.
+3. You may not pretend that you wrote this software. If you use it in a
+ program, you must acknowledge somewhere in your documentation that
+ you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose. This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-2013, Thomas G. Lane, Guido Vollbeding.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library. If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it. This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+The Unix configuration script "configure" was produced with GNU Autoconf.
+It is copyright by the Free Software Foundation but is freely distributable.
+The same holds for its supporting scripts (config.guess, config.sub,
+ltmain.sh). Another support script, install-sh, is copyright by X Consortium
+but is also freely distributable.
+
+The IJG distribution formerly included code to read and write GIF files.
+To avoid entanglement with the Unisys LZW patent, GIF reading support has
+been removed altogether, and the GIF writer has been simplified to produce
+"uncompressed GIFs". This technique does not use the LZW algorithm; the
+resulting GIF files are larger than usual, but are readable by all standard
+GIF decoders.
+
+We are required to state that
+ "The Graphics Interchange Format(c) is the Copyright property of
+ CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ CompuServe Incorporated."
+
+------------------------------------------------------------------------------
+
+Files: contrib/gdk-pixbuf/*
+
+Copyright 2020 Emmanuel Gil Peyrot. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/Dianoga/Dianoga Tools/avif/avifenc.exe b/src/Dianoga/Dianoga Tools/avif/avifenc.exe
new file mode 100644
index 00000000..1fe006ef
Binary files /dev/null and b/src/Dianoga/Dianoga Tools/avif/avifenc.exe differ
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.brotli b/src/Dianoga/Dianoga Tools/jxl/LICENSE.brotli
new file mode 100644
index 00000000..33b7cdd2
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.brotli
@@ -0,0 +1,19 @@
+Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.giflib b/src/Dianoga/Dianoga Tools/jxl/LICENSE.giflib
new file mode 100644
index 00000000..b9c0b501
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.giflib
@@ -0,0 +1,19 @@
+The GIFLIB distribution is Copyright (c) 1997 Eric S. Raymond
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.highway b/src/Dianoga/Dianoga Tools/jxl/LICENSE.highway
new file mode 100644
index 00000000..f49a4e16
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.highway
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.libjpeg-turbo b/src/Dianoga/Dianoga Tools/jxl/LICENSE.libjpeg-turbo
new file mode 100644
index 00000000..99c9aadc
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.libjpeg-turbo
@@ -0,0 +1,132 @@
+libjpeg-turbo Licenses
+======================
+
+libjpeg-turbo is covered by three compatible BSD-style open source licenses:
+
+- The IJG (Independent JPEG Group) License, which is listed in
+ [README.ijg](README.ijg)
+
+ This license applies to the libjpeg API library and associated programs
+ (any code inherited from libjpeg, and any modifications to that code.)
+
+- The Modified (3-clause) BSD License, which is listed below
+
+ This license covers the TurboJPEG API library and associated programs, as
+ well as the build system.
+
+- The [zlib License](https://opensource.org/licenses/Zlib)
+
+ This license is a subset of the other two, and it covers the libjpeg-turbo
+ SIMD extensions.
+
+
+Complying with the libjpeg-turbo Licenses
+=========================================
+
+This section provides a roll-up of the libjpeg-turbo licensing terms, to the
+best of our understanding.
+
+1. If you are distributing a modified version of the libjpeg-turbo source,
+ then:
+
+ 1. You cannot alter or remove any existing copyright or license notices
+ from the source.
+
+ **Origin**
+ - Clause 1 of the IJG License
+ - Clause 1 of the Modified BSD License
+ - Clauses 1 and 3 of the zlib License
+
+ 2. You must add your own copyright notice to the header of each source
+ file you modified, so others can tell that you modified that file (if
+ there is not an existing copyright header in that file, then you can
+ simply add a notice stating that you modified the file.)
+
+ **Origin**
+ - Clause 1 of the IJG License
+ - Clause 2 of the zlib License
+
+ 3. You must include the IJG README file, and you must not alter any of the
+ copyright or license text in that file.
+
+ **Origin**
+ - Clause 1 of the IJG License
+
+2. If you are distributing only libjpeg-turbo binaries without the source, or
+ if you are distributing an application that statically links with
+ libjpeg-turbo, then:
+
+ 1. Your product documentation must include a message stating:
+
+ This software is based in part on the work of the Independent JPEG
+ Group.
+
+ **Origin**
+ - Clause 2 of the IJG license
+
+ 2. If your binary distribution includes or uses the TurboJPEG API, then
+ your product documentation must include the text of the Modified BSD
+ License (see below.)
+
+ **Origin**
+ - Clause 2 of the Modified BSD License
+
+3. You cannot use the name of the IJG or The libjpeg-turbo Project or the
+ contributors thereof in advertising, publicity, etc.
+
+ **Origin**
+ - IJG License
+ - Clause 3 of the Modified BSD License
+
+4. The IJG and The libjpeg-turbo Project do not warrant libjpeg-turbo to be
+ free of defects, nor do we accept any liability for undesirable
+ consequences resulting from your use of the software.
+
+ **Origin**
+ - IJG License
+ - Modified BSD License
+ - zlib License
+
+
+The Modified (3-clause) BSD License
+===================================
+
+Copyright (C)2009-2020 D. R. Commander. All Rights Reserved.
+Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+- Neither the name of the libjpeg-turbo Project nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+Why Three Licenses?
+===================
+
+The zlib License could have been used instead of the Modified (3-clause) BSD
+License, and since the IJG License effectively subsumes the distribution
+conditions of the zlib License, this would have effectively placed
+libjpeg-turbo binary distributions under the IJG License. However, the IJG
+License specifically refers to the Independent JPEG Group and does not extend
+attribution and endorsement protections to other entities. Thus, it was
+desirable to choose a license that granted us the same protections for new code
+that were granted to the IJG for code derived from their software.
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.libjxl b/src/Dianoga/Dianoga Tools/jxl/LICENSE.libjxl
new file mode 100644
index 00000000..c66034b1
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.libjxl
@@ -0,0 +1,27 @@
+Copyright (c) the JPEG XL Project Authors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.libpng b/src/Dianoga/Dianoga Tools/jxl/LICENSE.libpng
new file mode 100644
index 00000000..e0c5b531
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.libpng
@@ -0,0 +1,134 @@
+COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
+=========================================
+
+PNG Reference Library License version 2
+---------------------------------------
+
+ * Copyright (c) 1995-2019 The PNG Reference Library Authors.
+ * Copyright (c) 2018-2019 Cosmin Truta.
+ * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
+ * Copyright (c) 1996-1997 Andreas Dilger.
+ * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
+
+The software is supplied "as is", without warranty of any kind,
+express or implied, including, without limitation, the warranties
+of merchantability, fitness for a particular purpose, title, and
+non-infringement. In no event shall the Copyright owners, or
+anyone distributing the software, be liable for any damages or
+other liability, whether in contract, tort or otherwise, arising
+from, out of, or in connection with the software, or the use or
+other dealings in the software, even if advised of the possibility
+of such damage.
+
+Permission is hereby granted to use, copy, modify, and distribute
+this software, or portions hereof, for any purpose, without fee,
+subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you
+ must not claim that you wrote the original software. If you
+ use this software in a product, an acknowledgment in the product
+ documentation would be appreciated, but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 3. This Copyright notice may not be removed or altered from any
+ source or altered source distribution.
+
+
+PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)
+-----------------------------------------------------------------------
+
+libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are
+Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are
+derived from libpng-1.0.6, and are distributed according to the same
+disclaimer and license as libpng-1.0.6 with the following individuals
+added to the list of Contributing Authors:
+
+ Simon-Pierre Cadieux
+ Eric S. Raymond
+ Mans Rullgard
+ Cosmin Truta
+ Gilles Vollant
+ James Yu
+ Mandar Sahastrabuddhe
+ Google Inc.
+ Vadim Barkov
+
+and with the following additions to the disclaimer:
+
+ There is no warranty against interference with your enjoyment of
+ the library or against infringement. There is no warranty that our
+ efforts or the library will fulfill any of your particular purposes
+ or needs. This library is provided with all faults, and the entire
+ risk of satisfactory quality, performance, accuracy, and effort is
+ with the user.
+
+Some files in the "contrib" directory and some configure-generated
+files that are distributed with libpng have other copyright owners, and
+are released under other open source licenses.
+
+libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from
+libpng-0.96, and are distributed according to the same disclaimer and
+license as libpng-0.96, with the following individuals added to the
+list of Contributing Authors:
+
+ Tom Lane
+ Glenn Randers-Pehrson
+ Willem van Schaik
+
+libpng versions 0.89, June 1996, through 0.96, May 1997, are
+Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,
+and are distributed according to the same disclaimer and license as
+libpng-0.88, with the following individuals added to the list of
+Contributing Authors:
+
+ John Bowler
+ Kevin Bracey
+ Sam Bushell
+ Magnus Holmgren
+ Greg Roelofs
+ Tom Tanner
+
+Some files in the "scripts" directory have other copyright owners,
+but are released under this license.
+
+libpng versions 0.5, May 1995, through 0.88, January 1996, are
+Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
+
+For the purposes of this copyright and license, "Contributing Authors"
+is defined as the following set of individuals:
+
+ Andreas Dilger
+ Dave Martindale
+ Guy Eric Schalnat
+ Paul Schmidt
+ Tim Wegner
+
+The PNG Reference Library is supplied "AS IS". The Contributing
+Authors and Group 42, Inc. disclaim all warranties, expressed or
+implied, including, without limitation, the warranties of
+merchantability and of fitness for any purpose. The Contributing
+Authors and Group 42, Inc. assume no liability for direct, indirect,
+incidental, special, exemplary, or consequential damages, which may
+result from the use of the PNG Reference Library, even if advised of
+the possibility of such damage.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+source code, or portions hereof, for any purpose, without fee, subject
+to the following restrictions:
+
+ 1. The origin of this source code must not be misrepresented.
+
+ 2. Altered versions must be plainly marked as such and must not
+ be misrepresented as being the original source.
+
+ 3. This Copyright notice may not be removed or altered from any
+ source or altered source distribution.
+
+The Contributing Authors and Group 42, Inc. specifically permit,
+without fee, and encourage the use of this source code as a component
+to supporting the PNG file format in commercial products. If you use
+this source code in a product, acknowledgment is not required but would
+be appreciated.
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.libwebp b/src/Dianoga/Dianoga Tools/jxl/LICENSE.libwebp
new file mode 100644
index 00000000..7a6f9954
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.libwebp
@@ -0,0 +1,30 @@
+Copyright (c) 2010, Google Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name of Google nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.sjpeg b/src/Dianoga/Dianoga Tools/jxl/LICENSE.sjpeg
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.sjpeg
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.skcms b/src/Dianoga/Dianoga Tools/jxl/LICENSE.skcms
new file mode 100644
index 00000000..6c7c5be3
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.skcms
@@ -0,0 +1,29 @@
+// Copyright (c) 2018 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------
diff --git a/src/Dianoga/Dianoga Tools/jxl/LICENSE.zlib b/src/Dianoga/Dianoga Tools/jxl/LICENSE.zlib
new file mode 100644
index 00000000..ca5fddfe
--- /dev/null
+++ b/src/Dianoga/Dianoga Tools/jxl/LICENSE.zlib
@@ -0,0 +1,20 @@
+ Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
\ No newline at end of file
diff --git a/src/Dianoga/Dianoga Tools/jxl/cjxl.exe b/src/Dianoga/Dianoga Tools/jxl/cjxl.exe
new file mode 100644
index 00000000..fdcd64e8
Binary files /dev/null and b/src/Dianoga/Dianoga Tools/jxl/cjxl.exe differ
diff --git a/src/Dianoga/Dianoga.csproj b/src/Dianoga/Dianoga.csproj
index 6693eb40..da40d63d 100644
--- a/src/Dianoga/Dianoga.csproj
+++ b/src/Dianoga/Dianoga.csproj
@@ -4,7 +4,7 @@
net452;net462;net471;net48
false
Automatic media library image file optimization for Sitecore
- 5.4.1
+ 6.0.0-beta.1
Kam Figy, Mark Gibbons
https://github.com/kamsar/Dianoga
MIT
@@ -83,8 +83,4 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/Dianoga/Dianoga.svgtools.nuspec b/src/Dianoga/Dianoga.svgtools.nuspec
index 189783cb..63a1ab02 100644
--- a/src/Dianoga/Dianoga.svgtools.nuspec
+++ b/src/Dianoga/Dianoga.svgtools.nuspec
@@ -2,7 +2,7 @@
Dianoga.svgtools
- 5.4.1
+ 6.0.0-beta.1
Dianoga.svgtools
Kam Figy, Mark Gibbons
Kam Figy, Mark Gibbons
@@ -14,7 +14,7 @@
Copyright 2021
sitecore image optimization
-
+
diff --git a/src/Dianoga/Invokers/GetMediaStreamSync/OptimizeImage.cs b/src/Dianoga/Invokers/GetMediaStreamSync/OptimizeImage.cs
index 61d6fc3a..2adaf93d 100644
--- a/src/Dianoga/Invokers/GetMediaStreamSync/OptimizeImage.cs
+++ b/src/Dianoga/Invokers/GetMediaStreamSync/OptimizeImage.cs
@@ -48,9 +48,9 @@ public void Process(GetMediaStreamPipelineArgs args)
args.OutputStream = optimizedOutputStream;
- if (optimizedOutputStream.Extension == "webp")
+ if (optimizedOutputStream.Extension == "webp" || optimizedOutputStream.Extension == "avif")
{
- // WebP processor has handled everything including resizing
+ // Further processing will fail
args.AbortPipeline();
}
}
diff --git a/src/Dianoga/NextGenFormats/Extensions.cs b/src/Dianoga/NextGenFormats/Extensions.cs
new file mode 100644
index 00000000..dada023d
--- /dev/null
+++ b/src/Dianoga/NextGenFormats/Extensions.cs
@@ -0,0 +1,33 @@
+using System.Web;
+using Sitecore.Resources.Media;
+
+namespace Dianoga.NextGenFormats
+{
+ public static class Extensions
+ {
+ static Extensions()
+ {
+ Helpers = new Helpers();
+ }
+
+ private static readonly Helpers Helpers;
+ public static void AddCustomOptions(this MediaRequest request, HttpContextBase context)
+ {
+ var customExtension = Helpers.GetCustomOptions(context);
+ if (!string.IsNullOrEmpty(customExtension))
+ {
+ request.Options.CustomOptions["extension"] = customExtension;
+ }
+ }
+
+ public static bool CheckSupportOfExtension(this HttpContextBase context, string extension)
+ {
+ return Helpers.CheckSupportedFormat(context, extension);
+ }
+
+ public static bool CheckSupportOfExtension(this MediaOptions mediaOptions, string extension)
+ {
+ return Helpers.CheckSupportedFormat(mediaOptions?.CustomOptions["extension"], extension);
+ }
+ }
+}
diff --git a/src/Dianoga/NextGenFormats/Helpers.cs b/src/Dianoga/NextGenFormats/Helpers.cs
new file mode 100644
index 00000000..c5e28968
--- /dev/null
+++ b/src/Dianoga/NextGenFormats/Helpers.cs
@@ -0,0 +1,42 @@
+using System.Linq;
+using System.Web;
+
+namespace Dianoga.NextGenFormats
+{
+ public class Helpers
+ {
+ public virtual PipelineHelpers PipelineHelpers { get; set; } = new PipelineHelpers();
+
+ public static bool CdnEnabled => Sitecore.Configuration.Settings.GetBoolSetting("Dianoga.CDN.Enabled", false);
+
+ public virtual string GetSupportedFormats(HttpContextBase context)
+ {
+ var acceptTypes = context?.Request?.AcceptTypes ?? new string[] { };
+ if (acceptTypes.Any())
+ {
+ return PipelineHelpers.RunDianogaGetSupportedFormatsPipeline(acceptTypes);
+ }
+
+ return string.Empty;
+ }
+
+ public virtual bool CheckSupportedFormat(HttpContextBase context, string extension)
+ {
+ var acceptTypes = context?.Request?.AcceptTypes ?? new string[] { };
+ return acceptTypes.Any() && CheckSupportedFormat(string.Join(",", acceptTypes), extension);
+ }
+
+ public virtual bool CheckSupportedFormat(string input, string extension)
+ {
+ return input?.Contains(extension) ?? false;
+ }
+
+ public virtual string GetCustomOptions(HttpContextBase context)
+ {
+ var requestExtension = context?.Request.QueryString?["extension"];
+ var customExtension = !string.IsNullOrEmpty(requestExtension) ? requestExtension : GetSupportedFormats(context);
+
+ return customExtension;
+ }
+ }
+}
diff --git a/src/Dianoga/WebP/MediaProvider.cs b/src/Dianoga/NextGenFormats/MediaProvider.cs
similarity index 56%
rename from src/Dianoga/WebP/MediaProvider.cs
rename to src/Dianoga/NextGenFormats/MediaProvider.cs
index 060fbe6f..08cd128d 100644
--- a/src/Dianoga/WebP/MediaProvider.cs
+++ b/src/Dianoga/NextGenFormats/MediaProvider.cs
@@ -3,7 +3,7 @@
using Sitecore.Resources.Media;
using Sitecore.Web;
-namespace Dianoga.WebP
+namespace Dianoga.NextGenFormats
{
#pragma warning disable CS0612 // Type or member is obsolete
public class MediaProvider : Sitecore.Resources.Media.MediaProvider
@@ -13,10 +13,7 @@ public override string GetMediaUrl(MediaItem item, MediaUrlOptions options)
{
var url = base.GetMediaUrl(item, options);
- if (item.MimeType.StartsWith("image") && HttpContext.Current.BrowserSupportsWebP() && !url.Contains("extension"))
- {
- url = WebUtil.AddQueryString(url, "extension", "webp");
- }
+ url = GetMediaUrl(item, url);
return url;
}
@@ -26,15 +23,26 @@ public override string GetMediaUrl(MediaItem item, Sitecore.Links.UrlBuilders.Me
{
var url = base.GetMediaUrl(item, options);
- if (item.MimeType.StartsWith("image") && HttpContext.Current.BrowserSupportsWebP() && !url.Contains("extension"))
- {
- url = WebUtil.AddQueryString(url, "extension", "webp");
- }
+ url = GetMediaUrl(item, url);
return url;
}
#endif
+ protected virtual string GetMediaUrl(MediaItem item, string url)
+ {
+ var helpers = new Helpers();
+ if (item.MimeType.StartsWith("image") && !url.Contains("extension"))
+ {
+ var extensions = helpers.GetSupportedFormats(new HttpContextWrapper(HttpContext.Current));
+ if (string.IsNullOrEmpty(extensions))
+ {
+ return WebUtil.AddQueryString(url, "extension", extensions);
+ }
+ }
+ return url;
+ }
+
}
#pragma warning restore CS0612 // Type or member is obsolete
}
diff --git a/src/Dianoga/MediaRequestHandler.cs b/src/Dianoga/NextGenFormats/MediaRequestHandler.cs
similarity index 53%
rename from src/Dianoga/MediaRequestHandler.cs
rename to src/Dianoga/NextGenFormats/MediaRequestHandler.cs
index c202603b..d7d2582a 100644
--- a/src/Dianoga/MediaRequestHandler.cs
+++ b/src/Dianoga/NextGenFormats/MediaRequestHandler.cs
@@ -1,20 +1,14 @@
-using System.Web;
-using Dianoga.WebP;
-using Sitecore.Resources.Media;
-
-namespace Dianoga
-{
- public class MediaRequestHandler : Sitecore.Resources.Media.MediaRequestHandler
- {
- protected override bool DoProcessRequest(HttpContext context, MediaRequest request, Media media)
- {
- if ((context?.Request.QueryString?["extension"]?.Contains("webp") ?? false) || (!Helpers.CdnEnabled && context.BrowserSupportsWebP()))
- {
- request.Options.CustomOptions["extension"] = "webp";
- }
-
- return base.DoProcessRequest(context, request, media);
- }
-
- }
-}
+using System.Web;
+using Sitecore.Resources.Media;
+
+namespace Dianoga.NextGenFormats
+{
+ public class MediaRequestHandler : Sitecore.Resources.Media.MediaRequestHandler
+ {
+ protected override bool DoProcessRequest(HttpContext context, MediaRequest request, Media media)
+ {
+ request.AddCustomOptions(new HttpContextWrapper(context));
+ return base.DoProcessRequest(context, request, media);
+ }
+ }
+}
diff --git a/src/Dianoga/MediaRequestHandlerXA.cs b/src/Dianoga/NextGenFormats/MediaRequestHandlerXA.cs
similarity index 70%
rename from src/Dianoga/MediaRequestHandlerXA.cs
rename to src/Dianoga/NextGenFormats/MediaRequestHandlerXA.cs
index f6c2c0eb..257eab01 100644
--- a/src/Dianoga/MediaRequestHandlerXA.cs
+++ b/src/Dianoga/NextGenFormats/MediaRequestHandlerXA.cs
@@ -1,27 +1,25 @@
-#if !NET452
-using System.Web;
-using Dianoga.WebP;
-using Sitecore.Pipelines;
-using Sitecore.XA.Foundation.MediaRequestHandler.Pipelines.MediaRequestHandler;
-
-namespace Dianoga
-{
- public class MediaRequestHandlerXA : Sitecore.XA.Foundation.MediaRequestHandler.MediaRequestHandler
- {
- protected override bool DoProcessRequest(HttpContext context)
- {
- var mediaRequestHandlerArgs = new MediaRequestHandlerArgs(context);
- CorePipeline.Run("mediaRequestHandler", mediaRequestHandlerArgs, failIfNotExists: false);
- if (mediaRequestHandlerArgs.Aborted)
- {
- return mediaRequestHandlerArgs.Result;
- }
- if ((context?.Request.QueryString?["extension"]?.Contains("webp") ?? false) || (!Helpers.CdnEnabled && context.BrowserSupportsWebP()))
- {
- mediaRequestHandlerArgs.Request.Options.CustomOptions["extension"] = "webp";
- }
- return DoProcessRequest(mediaRequestHandlerArgs.Context, mediaRequestHandlerArgs.Request, mediaRequestHandlerArgs.Media);
- }
- }
-}
+#if !NET452
+using System.Web;
+using Sitecore.Pipelines;
+using Sitecore.XA.Foundation.MediaRequestHandler.Pipelines.MediaRequestHandler;
+
+namespace Dianoga.NextGenFormats
+{
+ public class MediaRequestHandlerXA : Sitecore.XA.Foundation.MediaRequestHandler.MediaRequestHandler
+ {
+ protected override bool DoProcessRequest(HttpContext context)
+ {
+ var mediaRequestHandlerArgs = new MediaRequestHandlerArgs(context);
+ CorePipeline.Run("mediaRequestHandler", mediaRequestHandlerArgs, failIfNotExists: false);
+ if (mediaRequestHandlerArgs.Aborted)
+ {
+ return mediaRequestHandlerArgs.Result;
+ }
+
+ mediaRequestHandlerArgs.Request.AddCustomOptions(new HttpContextWrapper(context));
+
+ return DoProcessRequest(mediaRequestHandlerArgs.Context, mediaRequestHandlerArgs.Request, mediaRequestHandlerArgs.Media);
+ }
+ }
+}
#endif
\ No newline at end of file
diff --git a/src/Dianoga/NextGenFormats/PipelineHelpers.cs b/src/Dianoga/NextGenFormats/PipelineHelpers.cs
new file mode 100644
index 00000000..0d2b9741
--- /dev/null
+++ b/src/Dianoga/NextGenFormats/PipelineHelpers.cs
@@ -0,0 +1,19 @@
+using Sitecore.Pipelines;
+
+namespace Dianoga.NextGenFormats
+{
+ public class PipelineHelpers
+ {
+ public virtual string RunDianogaGetSupportedFormatsPipeline(string[] acceptTypes)
+ {
+ var nextGenFormats = new SupportedFormatsArgs()
+ {
+ Input = string.Join(",", acceptTypes),
+ Prefix = "image/"
+ };
+ CorePipeline.Run("dianogaGetSupportedFormats", nextGenFormats);
+
+ return string.Join(",", nextGenFormats.Extensions);
+ }
+ }
+}
diff --git a/src/Dianoga/NextGenFormats/Pipelines/CheckSupport.cs b/src/Dianoga/NextGenFormats/Pipelines/CheckSupport.cs
new file mode 100644
index 00000000..660c41de
--- /dev/null
+++ b/src/Dianoga/NextGenFormats/Pipelines/CheckSupport.cs
@@ -0,0 +1,20 @@
+namespace Dianoga.NextGenFormats.Pipelines.DianogaGetSupportedFormats
+{
+ public class CheckSupport
+ {
+ public virtual string Extension
+ {
+ get;
+ set;
+ }
+
+ public void Process(SupportedFormatsArgs args)
+ {
+ var supports = args.Input.Contains($"{args.Prefix}{Extension}"); ;
+ if (supports)
+ {
+ args.Extensions.Add(Extension);
+ }
+ }
+ }
+}
diff --git a/src/Dianoga/NextGenFormats/Pipelines/GenerateCacheKey.cs b/src/Dianoga/NextGenFormats/Pipelines/GenerateCacheKey.cs
new file mode 100644
index 00000000..83fe77b3
--- /dev/null
+++ b/src/Dianoga/NextGenFormats/Pipelines/GenerateCacheKey.cs
@@ -0,0 +1,26 @@
+using System.Web;
+using Sitecore.Diagnostics;
+using Sitecore.Mvc.Pipelines.Response.RenderRendering;
+
+namespace Dianoga.NextGenFormats.Pipelines
+{
+ public class GenerateCacheKey : RenderRenderingProcessor
+ {
+ public virtual string Extension
+ {
+ get;
+ set;
+ }
+
+ public override void Process(RenderRenderingArgs args)
+ {
+ Assert.ArgumentNotNull(args, nameof(args));
+ if (args.Rendered || !args.Cacheable || !NextGenFormats.Helpers.CdnEnabled)
+ return;
+
+ var extensionSupport = new HttpContextWrapper(HttpContext.Current).CheckSupportOfExtension(Extension);
+ var cacheKey = $"_#{Extension}:{extensionSupport}";
+ args.CacheKey += cacheKey;
+ }
+ }
+}
diff --git a/src/Dianoga/NextGenFormats/Pipelines/SupportedFormatsArgs.cs b/src/Dianoga/NextGenFormats/Pipelines/SupportedFormatsArgs.cs
new file mode 100644
index 00000000..5390fa38
--- /dev/null
+++ b/src/Dianoga/NextGenFormats/Pipelines/SupportedFormatsArgs.cs
@@ -0,0 +1,16 @@
+using Sitecore.Collections;
+using Sitecore.Pipelines;
+
+namespace Dianoga.NextGenFormats
+{
+ public class SupportedFormatsArgs : PipelineArgs
+ {
+ public SupportedFormatsArgs()
+ {
+ Extensions = new Set();
+ }
+ public Set Extensions { get; set; }
+ public string Input { get; set; }
+ public string Prefix { get; set; }
+ }
+}
diff --git a/src/Dianoga/WebP/WebPMedia.cs b/src/Dianoga/NextGenFormats/WebP/WebPMedia.cs
similarity index 93%
rename from src/Dianoga/WebP/WebPMedia.cs
rename to src/Dianoga/NextGenFormats/WebP/WebPMedia.cs
index 43bbb807..bbd6f2c5 100644
--- a/src/Dianoga/WebP/WebPMedia.cs
+++ b/src/Dianoga/NextGenFormats/WebP/WebPMedia.cs
@@ -1,6 +1,6 @@
using Sitecore.Resources.Media;
-namespace Dianoga.WebP
+namespace Dianoga.NextGenFormats.WebP
{
public class WebPMedia : ImageMedia
{
diff --git a/src/Dianoga/WebP/WebPThumbnailGenerator.cs b/src/Dianoga/NextGenFormats/WebP/WebPThumbnailGenerator.cs
similarity index 98%
rename from src/Dianoga/WebP/WebPThumbnailGenerator.cs
rename to src/Dianoga/NextGenFormats/WebP/WebPThumbnailGenerator.cs
index b3d1f4e8..5b74ba12 100644
--- a/src/Dianoga/WebP/WebPThumbnailGenerator.cs
+++ b/src/Dianoga/NextGenFormats/WebP/WebPThumbnailGenerator.cs
@@ -3,7 +3,7 @@
using Sitecore.Pipelines;
using Sitecore.Resources.Media;
-namespace Dianoga.WebP
+namespace Dianoga.NextGenFormats.WebP
{
public class WebPThumbnailGenerator : ThumbnailGenerator
{
diff --git a/src/Dianoga/Optimizers/Pipelines/DianogaAvif/AvifOptimizer.cs b/src/Dianoga/Optimizers/Pipelines/DianogaAvif/AvifOptimizer.cs
new file mode 100644
index 00000000..5b66cb17
--- /dev/null
+++ b/src/Dianoga/Optimizers/Pipelines/DianogaAvif/AvifOptimizer.cs
@@ -0,0 +1,31 @@
+using Dianoga.NextGenFormats;
+
+namespace Dianoga.Optimizers.Pipelines.DianogaAvif
+{
+ public class AvifOptimizer : CommandLineToolOptimizer
+ {
+ public readonly string Extension = "avif";
+
+ public override void Process(OptimizerArgs args)
+ {
+ if (args.MediaOptions.CheckSupportOfExtension(Extension))
+ {
+ base.Process(args);
+
+ if (args.IsOptimized)
+ {
+ args.Extension = Extension;
+
+ //If avif optimization was executed then abort running other optimizers
+ //because they don't accept avif input file format
+ args.AbortPipeline();
+ }
+ }
+ }
+
+ protected override string CreateToolArguments(string tempFilePath, string tempOutputPath)
+ {
+ return $"\"{tempFilePath}\" -o \"{tempOutputPath}\" ";
+ }
+ }
+}
diff --git a/src/Dianoga/Optimizers/Pipelines/DianogaJxl/JxlOptimizer.cs b/src/Dianoga/Optimizers/Pipelines/DianogaJxl/JxlOptimizer.cs
new file mode 100644
index 00000000..90f5fdda
--- /dev/null
+++ b/src/Dianoga/Optimizers/Pipelines/DianogaJxl/JxlOptimizer.cs
@@ -0,0 +1,32 @@
+using Dianoga.NextGenFormats;
+
+namespace Dianoga.Optimizers.Pipelines.DianogaJxl
+{
+ public class JxlOptimizer : CommandLineToolOptimizer
+ {
+ public readonly string Extension = "jxl";
+ public bool DisableResizing { get; set; }
+
+ public override void Process(OptimizerArgs args)
+ {
+ if (args.MediaOptions.CheckSupportOfExtension(Extension))
+ {
+ base.Process(args);
+
+ if (args.IsOptimized)
+ {
+ args.Extension = Extension;
+
+ //If Jpeg-XL optimization was executed then abort running other optimizers
+ //because they don't accept jxl input file format
+ args.AbortPipeline();
+ }
+ }
+ }
+
+ protected override string CreateToolArguments(string tempFilePath, string tempOutputPath)
+ {
+ return $"\"{tempFilePath}\" \"{tempOutputPath}\" ";
+ }
+ }
+}
diff --git a/src/Dianoga/Optimizers/Pipelines/DianogaWebP/WebPOptimizer.cs b/src/Dianoga/Optimizers/Pipelines/DianogaWebP/WebPOptimizer.cs
index 1d67412c..aaad7ef5 100644
--- a/src/Dianoga/Optimizers/Pipelines/DianogaWebP/WebPOptimizer.cs
+++ b/src/Dianoga/Optimizers/Pipelines/DianogaWebP/WebPOptimizer.cs
@@ -1,20 +1,21 @@
-using Dianoga.WebP;
+using Dianoga.NextGenFormats;
namespace Dianoga.Optimizers.Pipelines.DianogaWebP
{
public class WebPOptimizer : CommandLineToolOptimizer
{
+ public readonly string Extension = "webp";
public bool DisableResizing { get; set; }
public override void Process(OptimizerArgs args)
{
- if (args.MediaOptions.BrowserSupportsWebP())
+ if (args.MediaOptions.CheckSupportOfExtension(Extension))
{
base.Process(args);
if (args.IsOptimized)
{
- args.Extension = "webp";
+ args.Extension = Extension;
//If WebP optimization was executed then abort running other optimizers
//because they don't accept webp input file format
diff --git a/src/Dianoga/WebP/Helpers.cs b/src/Dianoga/WebP/Helpers.cs
deleted file mode 100644
index 3ca83374..00000000
--- a/src/Dianoga/WebP/Helpers.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-using System.Linq;
-using System.Web;
-using Sitecore.Resources.Media;
-
-namespace Dianoga.WebP
-{
- public static class Helpers
- {
- public static bool CdnEnabled => Sitecore.Configuration.Settings.GetBoolSetting("Dianoga.CDN.Enabled", false);
-
- public static bool BrowserSupportsWebP(this HttpContext context)
- {
- return context?.Request.AcceptTypes != null && context.Request.AcceptTypes.Contains("image/webp");
- }
-
- public static bool BrowserSupportsWebP(this MediaOptions mediaOptions)
- {
- return mediaOptions.GetCustomExtension() == "webp";
- }
-
- public static string GetCustomExtension(this MediaOptions mediaOptions)
- {
- return mediaOptions.CustomOptions["extension"];
- }
- }
-}
diff --git a/src/Dianoga/WebP/Pipelines/GenerateCacheKey.cs b/src/Dianoga/WebP/Pipelines/GenerateCacheKey.cs
deleted file mode 100644
index 60878b64..00000000
--- a/src/Dianoga/WebP/Pipelines/GenerateCacheKey.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Web;
-using Sitecore.Diagnostics;
-using Sitecore.Mvc.Pipelines.Response.RenderRendering;
-
-namespace Dianoga.WebP.Pipelines
-{
- public class GenerateCacheKey : RenderRenderingProcessor
- {
- public override void Process(RenderRenderingArgs args)
- {
- Assert.ArgumentNotNull(args, nameof(args));
- if (args.Rendered || !args.Cacheable)
- return;
-
- var webp = HttpContext.Current.BrowserSupportsWebP();
- var cacheKey = "_#webp:" + webp;
- args.CacheKey += cacheKey;
- }
- }
-}