Table of Contents

GIF

Egami reads GIF 87a and 89a files, with every disposal method, interlaced images, transparency, the loop count, comments, XMP and ICC profiles, and writes GIF 89a.

Reading

A GIF loads as Rgba8, every frame composited to full size as a browser shows it. Damaged files load as far as they can, with the warnings the Diagnostics page lists under Gif..

GIF files keep their palettes, version and application extensions in GifDetails, and each frame's in GifFrameDetails:

using Raster<Rgba8> clip = Raster.Load<Rgba8>("pan.gif");
GifDetails details = (GifDetails)clip.Metadata.FormatDetails!;
Console.WriteLine($"GIF{details.Version}, {details.GlobalPalette.Length} global colors, repeats {details.RepetitionCount}");
foreach (GifApplicationExtension extension in details.OtherExtensions)
{
    Console.WriteLine($"Kept extension {extension.Identifier}: {extension.Data.Length} bytes");
}

foreach (Frame<Rgba8> frame in clip.Frames)
{
    if (frame.Metadata.FormatDetails is GifFrameDetails frameDetails)
    {
        Console.WriteLine($"Frame: {frameDetails.LocalPalette.Length} local colors, transparent index {frameDetails.TransparentIndex}");
    }
}

Writing

using FileStream output = File.Create("duck.gif");
photo.Save(output, GifFormat.Info, new GifWriterOptions
{
    Palette = new PaletteOptions { MaxColors = 128, Dither = DitherMode.Ordered }, // FloydSteinberg (default), Ordered or None
    PaletteScope = GifPaletteScope.PerFrame,   // Auto (default): one table when all frames fit, else one per frame
});

GIF holds at most 256 colors per frame. Frames with few enough colors keep them exactly. Others get a palette from Wu's quantizer, dithered with Floyd–Steinberg by default. GIF transparency is on or off, so pixels below PaletteOptions.AlphaThreshold (128 by default) become transparent.

Option Default Does
Palette 256 colors, Floyd–Steinberg How a palette is built when a frame has more colors than fit; see Palettes and dithering
PaletteScope Auto One global table when all frames fit in it, else one per frame; Global and PerFrame choose
OptimizeFrames true Each frame after the first stores only the rectangle that changed; false writes every frame whole

Saving a raster with more than one frame writes an animation; see the animation guide.