Magick.NET
| Language | C# (.NET 8+, .NET Standard 2.0, .NET Framework 4.6.2+) |
|---|---|
| License | Apache 2.0 (ImageMagick: ImageMagick License, permissive) |
| Repository | github.com/dlemstra/Magick.NET |
| Documentation | Magick.NET docs and samples |
| Depends on | native ImageMagick, bundled in the NuGet package (Windows, Linux, macOS; x64 and arm64) |
| Read / write | yes / yes; baseline, progressive, arithmetic, CMYK, 12-bit; Exif, XMP, IPTC, ICC |
Magick.NET puts the whole of ImageMagick, with its own copy of libjpeg-turbo, into a NuGet package. For JPEG it exposes everything libjpeg can do: quality, progressive (interlaced) output, sampling factors, Huffman optimization, custom quantization tables, and a size hint that makes the decoder scale down while loading. It also handles PNG, GIF, WebP, HEIC, TIFF, PDF (with Ghostscript) and 100+ other formats.
The native library makes the package large (about 15-30 MB per platform). Pick the Q8 package for 8-bit images like JPEG: it uses half the memory of Q16.
Installation#
dotnet add package Magick.NET-Q8-AnyCPU
Basic usage: auto-orient, resize and save as JPEG#
using ImageMagick;
using var image = new MagickImage("in.jpg");
Console.WriteLine($"{image.Width} x {image.Height}");
image.AutoOrient(); // apply the Exif orientation
image.Resize(new MagickGeometry("1200x>")); // width 1200, only shrink, keep aspect ratio
image.Quality = 85;
image.Write("out.jpg");
How to get JPEG dimensions without decoding#
var info = new MagickImageInfo("in.jpg");
Console.WriteLine($"{info.Width} x {info.Height}, {info.Format}, quality {info.Quality}");
Quality is ImageMagick’s estimate of the quality the file was saved with, computed from its quantization tables.
How to read Exif data#
using ImageMagick;
using var image = new MagickImage("photo.jpg");
IExifProfile? exif = image.GetExifProfile();
if (exif != null)
{
Console.WriteLine($"Camera: {exif.GetValue(ExifTag.Model)?.Value}");
Console.WriteLine($"Taken: {exif.GetValue(ExifTag.DateTimeOriginal)?.Value}");
foreach (IExifValue value in exif.Values)
Console.WriteLine($"{value.Tag}: {value.GetValue()}");
}
How to write a progressive JPEG with 4:4:4 sampling#
image.Quality = 90;
image.Settings.Interlace = Interlace.Jpeg; // progressive
image.Write("out.jpg", new JpegWriteDefines
{
SamplingFactor = JpegSamplingFactor.Ratio444,
OptimizeCoding = true,
});
How to make thumbnails of large JPEGs quickly#
The jpeg:size hint lets libjpeg decode at ½, ¼ or 1/8 scale, so a 24-megapixel photo loads in a fraction of the time:
var settings = new MagickReadSettings
{
Defines = new JpegReadDefines { Size = new MagickGeometry(400, 400) },
};
using var image = new MagickImage("big.jpg", settings);
image.AutoOrient();
image.Thumbnail(200, 200); // resize and strip metadata
image.Write("thumb.jpg");
How to remove metadata#
image.Strip(); // removes Exif, XMP, IPTC, comments and the ICC profile
image.Write("clean.jpg");
To keep the color profile, remove profiles one by one instead: image.RemoveProfile("exif"), image.RemoveProfile("xmp").
Tips#
- Set
MagickNET.SetTempDirectoryand resource limits (ResourceLimits.Memory,ResourceLimits.Width) on servers that handle untrusted uploads. image.Format = MagickFormat.JpegbeforeWrite(stream)chooses the output format when there’s no file extension.- Convert CMYK JPEGs for the web with
image.TransformColorSpace(ColorProfiles.SRGB)orimage.ColorSpace = ColorSpace.sRGB.