Announcing ImageSharp 3.0.0

ImageSharp 3 - An elegant weapon for a more civilized age

We are very excited to announce the release of ImageSharp 3.0.0 final. You can download it today.

This release is the culmination of nearly 9 months of work and marks a major shift in the development of ImageSharp.

With V3 we've changed the target framework to support the latest .NET 6 LTS.

By removing support for legacy frameworks we've been able to delete a lot of old code that was preventing us from providing much needed improvements throughout the library. As a result we've been able to simplify many of our internal and public APIs and deliver incredible performance improvements in several areas.

Going forward each major version will only support the current .NET LTS.

Don't worry! The V2 package is not going anywhere so if you cannot update your target framework we've still got you covered.

V3 will also be the first version to use the new Six Labors Split License.

What's new since V2. #

As ever we've been very busy!

  • Introduced new ImageDecoder and ImageEncoder base types that make custom implementations an order of magnitude easier.
  • Introduced border wrapping modes for all convolution operations - This allows tiling of output operations.
  • Introduced a new Median Blur processor.
  • Added support for decoding Jpegs with arithmetic encoding.
  • Added support for Fast IDCT Scaling to the jpeg decoder (more on that below).
  • We now preserve the ICC Profile when working with Webp, Bmp, and Png images.
  • Expanded support for Tiff to cover many additional encoding formats.
  • Fixed issues with our Gif format that resulted in malformed multi-frame Gifs.
  • Fixed issues with our WebP format which resulted in larger than expected files when encoding lossy output with alpha data.
  • Much much more....

Please read the release notes for detailed release information.

Breaking Changes #

We try to avoid breaking changes when we can but this release contains a few major ones that we really needed to make to ensure the future success of the library.

  • We've introduce support for Nullable Reference Types across all our APIs which will change the method signatures in several places.
  • We've completely overhauled and simplified our general decoding API and have introduced new shared options for all our decoders that allow controlling the decoding operation (more on that below).

DecoderOptions - The Weapon of a Jedi Knight #

The newly introduced DecoderOptions provide developers a powerful way to instruct our load APIs in a normalized fashion. These options are accessible to all our decoders and allow us to do some very cool things.

For example, the following code allows us to return the decoded image comprised of a single frame at the requested maximum size in each direction. For jpeg this is especially useful as it allows us to take advantage of super fast IDCT scaling operations within the format that give us an impressive performance boost and uses less memory in the process.

The image is saved using the same image format using information added to the metadata following the decoding operation.

DecoderOptions options = new()
{
    MaxFrames = 1,
    TargetSize = new(150, 150)
};

using var image = Image.Load(options, inputStream);
image.Save(outputStream, image.Metadata.DecodedImageFormat);

To demonstrate how much of a performance improvement this offers. Here's a run of that old classic benchmark from back in 2017

I'm running this on my Surface Laptop Studio called Stormbreaker with 32 GB of RAM.

Note. I couldn't get the native memory profiler to work so the benchmark is missing the total allocated memory for most of the other libraries. You can see the benchmarks from V2 which capture that data

BenchmarkDotNet=v0.13.5, OS=Windows 11 (10.0.22621.1265/22H2/2022Update/SunValley2)
11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=7.0.200
  [Host]   : .NET 7.0.3 (7.0.323.6910), X64 RyuJIT AVX2
  ShortRun : .NET 7.0.3 (7.0.323.6910), X64 RyuJIT AVX2

Job=ShortRun  Arguments=/p:DebugType=portable  IterationCount=5
LaunchCount=1  WarmupCount=5

|                              Method |      Mean |     Error |   StdDev | Ratio | Allocated native memory | Native memory leak |      Gen0 |      Gen1 |      Gen2 |  Allocated | Alloc Ratio |
|------------------------------------ |----------:|----------:|---------:|------:|------------------------:|-------------------:|----------:|----------:|----------:|-----------:|------------:|
| 'System.Drawing Load, Resize, Save' | 366.86 ms | 11.545 ms | 2.998 ms |  1.00 |               11,378 KB |             738 KB |         - |         - |         - |   13.42 KB |        1.00 |
|     'ImageSharp Load, Resize, Save' | 117.77 ms |  2.567 ms | 0.667 ms |  0.32 |                    9 KB |                  - |         - |         - |         - | 1319.65 KB |       98.32 |
|  'ImageSharp TD Load, Resize, Save' |  76.26 ms |  4.433 ms | 0.686 ms |  0.21 |                    9 KB |                  - |         - |         - |         - |  575.86 KB |       42.90 |
|    'ImageMagick Load, Resize, Save' | 393.91 ms |  8.088 ms | 2.101 ms |  1.07 |               61,712 KB |                  - |         - |         - |         - |   55.37 KB |        4.13 |
|      'ImageFree Load, Resize, Save' | 238.85 ms |  3.362 ms | 0.873 ms |  0.65 |               49,138 KB |                  - | 6000.0000 | 6000.0000 | 6000.0000 |   94.66 KB |        7.05 |
|    'MagicScaler Load, Resize, Save' |  64.26 ms |  1.008 ms | 0.262 ms |  0.18 |                3,067 KB |                  - |         - |         - |         - |    45.4 KB |        3.38 |
|      'SkiaSharp Load, Resize, Save' | 134.46 ms |  2.292 ms | 0.595 ms |  0.37 |               70,426 KB |             266 KB |         - |         - |         - |   86.93 KB |        6.48 |
|        'NetVips Load, Resize, Save' | 145.53 ms |  5.268 ms | 1.368 ms |  0.40 |               28,072 KB |               0 KB |         - |         - |         - |  122.45 KB |        9.12 |

// * Legends *
  Mean                    : Arithmetic mean of all measurements
  Error                   : Half of 99.9% confidence interval
  StdDev                  : Standard deviation of all measurements
  Ratio                   : Mean of the ratio distribution ([Current]/[Baseline])
  Allocated native memory : Allocated native memory per single operation
  Native memory leak      : Native memory leak size in byte.
  Gen0                    : GC Generation 0 collects per 1000 operations
  Gen1                    : GC Generation 1 collects per 1000 operations
  Gen2                    : GC Generation 2 collects per 1000 operations
  Allocated               : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
  Alloc Ratio             : Allocated memory ratio distribution ([Current]/[Baseline])
  1 ms                    : 1 Millisecond (0.001 sec)

ImageSharp TD Load, Resize, Save is the line of interest here.

Pretty neat eh? ImageSharp can give you some pretty serious performance gains for that scenario.

In addition to the general decoding API we offer additional specialized decoding options ISpecializedDecoderOptions that can be accessed directly against ISpecializedDecoder<T> instances which provide further options for decoding.

A perfect balance of simplicity and power!

Performance #

Performance has always been a feature of ImageSharp and we're always looking for ways to squeeze out improvements across the entire library in each release. This release is no different with many improvements across several areas.

One of the areas that has long been a point of interest and a known performance issue has been our handling of alpha compositing.

From Wikipedia

In computer graphics, alpha compositing or alpha blending is the process of combining one image with a background to create the appearance of partial or full transparency. It is often useful to render picture elements (pixels) in separate passes or layers and then combine the resulting 2D images into a single, final image called the composite. Compositing is used extensively in film when combining computer-rendered image elements with live footage. Alpha blending is also used in 2D computer graphics to put rasterized foreground elements over a background.

Alpha compositing is the backbone for any blending operation. This covers the simple act of overlaying an image to all complex drawing operations (think lines, curves, brushes, pens, text). In V2 this was a bottleneck for all those operations and greatly hindered our ability to ship an additional drawing package.

In V3 we've blown things out of the water and improved performance by a whopping 14.4x!

This was achieved by conducting a complete overhaul of the existing Vector4 implementation (6.1x faster than the previous implementation) and introducing a new AVX2 pipeline which brings improvement to 14.4x.

This change will allow us to complete the ImageSharp.Drawing library safe in the knowledge that we can bring excellent performance to the table.

In addition to those changes we've introduced a 2x speedup for all operations involving our ColorMatrix type. This brings great improvement across all our filtering methods including adjustments for brightness and contrast.

The Future #

We'll be publishing new releases over the next few days of all our libraries that depend on ImageSharp. That means a new major version SixLabors.ImageSharp.Web.

We'll also concentrate on shipping V1 versions of SixLabors.ImageSharp.Drawing and SixLabors.Fonts targeting a release date in the first half of this year.

Closing #

Thanks again for all the feedback and usage. It's been a pleasure to build ImageSharp so far and to see so many people try it out; we really appreciate it. Please continue exploring the product and learning what it's capable of.