Magick.NET
| Language | C# (.NET Standard 2.0, .NET 8+) |
|---|---|
| License | Apache-2.0 (ImageMagick license for the native part) |
| Repository | github.com/dlemstra/Magick.NET |
| Documentation | Magick.NET docs |
| Depends on | native ImageMagick with libjxl, included in the NuGet package |
| Read / write | yes / yes, lossy and lossless, animation |
Magick.NET is the .NET wrapper of ImageMagick. Its NuGet packages contain native ImageMagick builds with libjxl for Windows, Linux and macOS (x64 and arm64), so .jxl files open like any other image format. It’s a good fit when an application already handles many image formats and needs JPEG XL as one more.
It decodes the whole image into memory and has no API for lossless JPEG recompression: converting a JPEG to JXL with Magick.NET decodes and re-encodes the pixels. Use the cjxl tool or libjxl for bit-exact JPEG transcoding.
Installation#
dotnet add package Magick.NET-Q8-AnyCPU
Use Magick.NET-Q16-AnyCPU (16 bits per channel) or Magick.NET-Q16-HDRI-AnyCPU (floating point) for high bit depth and HDR images. Packages for a single platform (-x64, -arm64) are smaller.
Basic usage: read a JXL file and save it as PNG#
using ImageMagick;
using var image = new MagickImage("in.jxl");
Console.WriteLine($"{image.Width} x {image.Height}, depth {image.Depth}, alpha {image.HasAlpha}");
image.Write("out.png");
How to convert an image to JPEG XL#
Quality uses a JPEG-like 0-100 scale; 100 means lossless.
using ImageMagick;
using var image = new MagickImage("photo.png");
image.Quality = 90;
image.Write("photo.jxl"); // the format comes from the extension
To write to a stream or byte array, set the format explicitly:
image.Format = MagickFormat.Jxl;
byte[] data = image.ToByteArray();
How to save a lossless JPEG XL#
using var image = new MagickImage("screenshot.png");
image.Quality = 100; // distance 0: lossless
image.Write("screenshot.jxl");
How to set encoding effort and distance#
ImageMagick passes these defines to libjxl:
using var image = new MagickImage("photo.png");
image.Settings.SetDefine(MagickFormat.Jxl, "effort", "9"); // 3-9, slower = smaller
image.Settings.SetDefine(MagickFormat.Jxl, "distance", "1.0"); // 0 = lossless, 1 = visually lossless
image.Write("photo.jxl");
How to get JXL dimensions without decoding pixels#
var info = new MagickImageInfo("in.jxl");
Console.WriteLine($"{info.Width} x {info.Height}, format {info.Format}");
How to read the frames of an animated JXL#
using var frames = new MagickImageCollection("anim.jxl");
foreach (var frame in frames)
Console.WriteLine($"{frame.Width} x {frame.Height}, delay {frame.AnimationDelay}");
frames.Write("anim.gif");
Tips#
- Check
MagickNET.SupportedFormatsforMagickFormat.Jxlto confirm that your build has JXL support. - Exif and XMP are kept when converting: read them with
image.GetExifProfile()andimage.GetXmpProfile().