ImageSharp 4.1.0 is out. You can download it today.
ImageSharp 4.1.0 adds a complete Windows animated cursor codec, a family of premultiplied pixel formats, and the full W3C blend mode set. It also rebuilds the SIMD layer on TensorPrimitives, decodes Apple CgBI PNG files, and hardens decoders across the formats people feed it every day.
What's new since 4.0.0 #
The main changes since 4.0.0 are:
- ANI decoding and encoding, completing the Windows icon family that started with built-in ICO and CUR support in V4.
- Seven premultiplied pixel formats plus a new
RgbaHalfformat, with an alpha-representation-aware conversion contract onIPixel. - Nine new color blending modes, completing the W3C blend mode set, plus a
Plusalpha composition mode. - SIMD pipelines normalized onto
TensorPrimitives, with AVX-512 paths, kernel operations up to 14.9x faster, and a 40% smaller managed assembly. - Decode support for Apple CgBI PNG files.
- Simplified aliased rendering:
GraphicsOptions.AntialiasThresholdis gone, and binary coverage is now exact. - Configurable and extensible memory allocator limits, including a cap for single contiguous buffers.
- Fixes across TIFF, GIF, PBM, EXIF, ICO, resize, and convolution paths.
Windows animated cursors #
V4 added ICO and CUR. 4.1 completes the family with ANI, the RIFF-based Windows animated cursor format.
The codec reads and writes the full container:
- embedded CUR, ICO, or BMP frame resources
- the
seqchunk that maps animation steps to resources - per-step timing from the
ratechunk - hotspots, and the name and artist metadata
Decoding projects every animation step onto a shared canvas, so multi-resolution cursor resources survive a round trip.
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Ani;
using SixLabors.ImageSharp.PixelFormats;
using Image<Rgba32> image = Image.Load<Rgba32>("frame-source.png");
AniFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetAniMetadata();
frameMetadata.FrameDelay = 10; // Sixtieths of a second.
frameMetadata.HotspotX = 4;
frameMetadata.HotspotY = 4;
image.SaveAsAni("pointer.ani");
ANI registers as a built-in format, so detection, Image.Identify(), and format conversion work the same way they do for every other codec. This work started as a community contribution, and we are grateful for it.
Premultiplied pixel formats #
GPU pipelines and compositors work in associated (premultiplied) alpha. Until now, moving pixel data between ImageSharp and those systems meant a conversion pass at the boundary.
4.1 adds pixel formats that store associated alpha natively: Rgba32P, Bgra32P, Argb32P, Abgr32P, RgbaHalfP, HalfVector4P, and NormalizedByte4P. A new straight-alpha RgbaHalf format joins them. RgbaHalf and RgbaHalfP are binary-compatible with the DXGI_FORMAT_R16G16B16A16_FLOAT GPU format.
The formats are only part of the change. IPixel now carries an alpha-representation-aware conversion contract, and the pixel blenders include dedicated associated-alpha Porter-Duff implementations at every SIMD width. Blending an associated format never round-trips through straight alpha.
ImageSharp.Drawing 3.1 builds on this directly: its WebGPU render targets can render premultiplied and read back into the matching P format without conversion.
The complete blend mode set #
PixelColorBlendingMode previously stopped at HardLight. 4.1 adds ColorDodge, ColorBurn, SoftLight, Difference, Exclusion, and the non-separable Hue, Saturation, Color, and Luminosity modes. That completes the W3C blend mode set, alongside the existing Add and Subtract.
PixelAlphaCompositionMode gains Plus, which adds source and destination with clamping. It is the standard operator for additive light effects.
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
GraphicsOptions options = new()
{
ColorBlendingMode = PixelColorBlendingMode.SoftLight,
AlphaCompositionMode = PixelAlphaCompositionMode.SrcOver
};
The immediate driver is COLRv1 color glyph rendering, which composites paint layers with exactly these modes. Every mode is implemented across straight-alpha and associated-alpha blenders, and tests confirm the two paths produce identical results.
SIMD through TensorPrimitives #
4.1 moves a large amount of hand-written SIMD onto System.Numerics.Tensors.TensorPrimitives, with a compatibility implementation covering the operations the BCL does not expose.
Gaussian and Bokeh blur kernel normalization, sharpening, and histogram offsets now run through tensor operations. JPEG ICC color conversion was flattened, ICC LUT normalization optimized, byte tensor addition uses AVX-512 where available, and the pixel blender hierarchy was flattened. PNG filter encoding, packed pixel conversion shuffles, and stateful Vector4 transforms were normalized onto the same helpers.
The gains are large where the old code was scalar or narrow. Every row below measured zero managed allocation:
| Operation | Elements | Before | After | Change |
|---|---|---|---|---|
| Histogram add | 65,536 | 24.43 μs | 1.64 μs | 14.9x faster |
| ICC byte LUT normalization | 256 | 145.2 ns | 10.0 ns | 14.5x faster |
| Sharpen-kernel negate | 161 | 83.4 ns | 4.7 ns | 94.3% faster |
| Gaussian normalization | 161 | 88.2 ns | 7.0 ns | 92.0% faster |
| JPEG normalize + interleave 4 | 4,096 | 2,959 ns | 1,108 ns | 62.6% faster |
| ICC max | 2,048 | 230.4 ns | 96.9 ns | 57.9% faster |
Not every case wins. A few small fixed-size kernels pay a dispatch cost, and the PNG up-filter crosses over to a win at 2 KB scanlines. The complete before-and-after tables are in the pull request.
Removing the replaced generated SIMD code also cut the managed assembly from 4,100,608 to 2,433,024 bytes, a 40.7% reduction.
Apple CgBI PNGs #
The PNG decoder now reads Apple CgBI files, the iOS-optimized variant that pngcrush -iphone produces. These files store raw DEFLATE image data, swap the channel order, and premultiply color by alpha. ImageSharp detects the CgBI chunk and reverses those changes automatically, with SIMD-accelerated scanline restoration and chunk-order validation. No decoder option is required, and the encoder always writes standard PNG output. This support also came through community contributions.
Simpler aliased rendering #
GraphicsOptions.AntialiasThreshold has been removed. When Antialias is false, coverage is now exact: a pixel is fully covered or not covered, with nothing to tune. ImageSharp.Drawing 3.1 pairs this with center-sampled aliased rasterization, so binary-coverage output matches classic rasterizers instead of depending on a threshold value.
If you set AntialiasThreshold in existing code, delete the assignment. No other action is needed.
Configurable allocator limits #
MemoryAllocatorOptions gains SingleBufferAllocationLimitMegabytes, which caps the size of one contiguous buffer alongside the existing group and accumulative limits. The resolved limits are now public on MemoryAllocator, so custom allocator implementations can enforce the same policies the default allocator does.
Fixes and hardening #
4.1 also fixes a set of real-world issues:
- TIFF ICC, EXIF, and XMP profiles are cloned into image metadata during decode, so they survive re-encoding to other formats.
- EXIF Long values now accept
ulongwrites within range. - GIF transparency handling and dithering were corrected for frames with transparent palette entries.
- ICO directory entries pointing at the end of the stream are rejected instead of producing empty frames.
- ANI decoding handles oversized chunks and partial icon masks without over-allocating.
- PBM decoding validates the declared maximum pixel value.
- Binary PGM and PPM files with 16-bit samples now decode and encode with the correct big-endian byte order.
- Resizing to a single pixel row or column no longer trips the transform degeneracy check.
- Convolutions over very small bounds compute correct sampling offsets.
- AOT compilation seeds cover the ICO, CUR, and QOI formats, fixing NativeAOT trimming of their generic pipelines.
Closing #
4.1 is a focused release: one new codec, new premultiplied pixel formats, the complete blend mode set, and a faster, more uniform SIMD core. The target framework and the license terms do not change.
Please read the release notes for detailed information.
Thank you to everyone who used the previews, reported issues, and contributed code to this release.
- Next: Announcing ImageSharp.Drawing 3.1.0
- Previous: Announcing Fonts 3.1.0