All formats

Magick.NET

LanguageC# (.NET 8+, .NET Standard 2.0, .NET Framework 4.6.2+)
LicenseApache 2.0 (ImageMagick: ImageMagick License, permissive)
Repositorygithub.com/dlemstra/Magick.NET
DocumentationMagick.NET docs and samples
Depends onnative ImageMagick, bundled in the NuGet package
Read / writeyes / yes; animation, transparency, frame optimization, quantization with dithering

Magick.NET reads an animated GIF into a MagickImageCollection, one MagickImage per frame. Frames come as stored in the file: each may be a smaller rectangle placed at Page.X/Page.Y on the canvas. Coalesce() turns them into full-canvas frames you can edit; Optimize() and OptimizeTransparency() turn them back into small difference frames before saving. ImageMagick’s quantizer with Floyd-Steinberg or Riemersma dithering produces good palettes from RGB frames.

The native library makes the package large. Use the Q8 package for GIF: it needs half the memory of Q16.

Installation#

Shell
dotnet add package Magick.NET-Q8-AnyCPU

Basic usage: read the frames of an animated GIF#

C#
using ImageMagick;

using var frames = new MagickImageCollection("anim.gif");
Console.WriteLine($"{frames.Count} frames, loop {frames[0].AnimationIterations} (0 = forever)");
foreach (var frame in frames)
{
    Console.WriteLine($"{frame.Width}x{frame.Height} at ({frame.Page.X},{frame.Page.Y}), " +
                      $"delay {frame.AnimationDelay}/100 s, dispose {frame.GifDisposeMethod}");
}

How to resize an animated GIF#

Coalesce first, or partial frames are scaled and placed wrongly:

C#
using var frames = new MagickImageCollection("anim.gif");
frames.Coalesce();                      // full-canvas frames
foreach (var frame in frames)
    frame.Resize(new MagickGeometry("320x"));   // width 320, keep aspect ratio
frames.Optimize();                      // back to small difference frames
frames.Write("small.gif");

How to create an animated GIF from images#

C#
using ImageMagick;

using var collection = new MagickImageCollection();
foreach (var file in new[] { "f1.png", "f2.png", "f3.png" })
{
    var image = new MagickImage(file);
    image.AnimationDelay = 20;          // 1/100 s units: 0.2 s
    image.GifDisposeMethod = GifDisposeMethod.Background;
    collection.Add(image);
}
collection[0].AnimationIterations = 0;  // loop forever

collection.Quantize(new QuantizeSettings { Colors = 256, DitherMethod = DitherMethod.FloydSteinberg });
collection.Optimize();
collection.Write("anim.gif");

How to make a GIF file smaller#

C#
using var frames = new MagickImageCollection("big.gif");
frames.Coalesce();
frames.Quantize(new QuantizeSettings { Colors = 64, DitherMethod = DitherMethod.No });
frames.Optimize();                // crop frames to changed areas
frames.OptimizeTransparency();    // make unchanged pixels transparent
frames.Write("smaller.gif");

How to extract the first frame or all frames#

C#
using var frames = new MagickImageCollection("anim.gif");
frames.Coalesce();
frames[0].Write("first.png");
for (int i = 0; i < frames.Count; i++)
    frames[i].Write($"frame-{i:D3}.png");

Tips#