Sdcb.SimdCodecs.Gif
1.2.0
Prefix Reserved
dotnet add package Sdcb.SimdCodecs.Gif --version 1.2.0
NuGet\Install-Package Sdcb.SimdCodecs.Gif -Version 1.2.0
<PackageReference Include="Sdcb.SimdCodecs.Gif" Version="1.2.0" />
<PackageVersion Include="Sdcb.SimdCodecs.Gif" Version="1.2.0" />
<PackageReference Include="Sdcb.SimdCodecs.Gif" />
paket add Sdcb.SimdCodecs.Gif --version 1.2.0
#r "nuget: Sdcb.SimdCodecs.Gif, 1.2.0"
#:package Sdcb.SimdCodecs.Gif@1.2.0
#addin nuget:?package=Sdcb.SimdCodecs.Gif&version=1.2.0
#tool nuget:?package=Sdcb.SimdCodecs.Gif&version=1.2.0
Sdcb.SimdCodecs.Gif
Pure-managed GIF (87a / 89a) decoding and encoding for .NET 10, derived from the GIF89a specification: global and local colour tables, interlacing, transparency, every disposal method and the NETSCAPE2.0 loop count. A frame is the whole canvas as a viewer shows it, every earlier frame composited in.
using Sdcb.SimdCodecs.Gif;
byte[] data = File.ReadAllBytes("image.gif");
GifInfo info = GifDecoder.ReadInfo(data); // canvas, frame count, alpha, loop count
GifImage first = GifDecoder.Decode(data); // the first frame, RGBA
Every frame, by index or in order, through the Sdcb.SimdCodecs frame reader:
using Sdcb.SimdCodecs;
using Sdcb.SimdCodecs.Abstractions;
if (SimdCodecs.TryOpenFrames(data, out IImageFrameReader? reader))
using (reader)
{
var buffer = new byte[info.Width * info.Height * 4];
foreach (FrameTiming frame in reader.EnumerateFramesInto(buffer, 0, ImagePixelFormat.Bgra32))
Show(buffer, frame.Duration);
}
Encoding
byte[] gif = GifEncoder.Encode(rgba, width, height, channels: 4);
byte[] animation = GifEncoder.EncodeAnimation(
[new GifAnimationFrame(frame0, TimeSpan.FromMilliseconds(100)), new GifAnimationFrame(frame1, TimeSpan.FromMilliseconds(100))],
width, height, channels: 4, new GifEncodeOptions { LoopCount = 0, Dither = true });
GIF holds at most 256 colours and 1-bit transparency, so the encoder:
- treats alpha below 128 as transparent, the rest as opaque;
- uses one global palette for every frame: exact (lossless) when the opaque colours of all frames fit in 256,
or 255 beside a transparent index; otherwise built by Wu's variance-minimising quantizer, with optional
Floyd–Steinberg dithering (
Dither); - writes an opaque animation's frames as the rectangle that changed, unchanged pixels as the transparent index; an animation with transparency writes whole frames, each cleared before the next;
- takes
LoopCountas plays (0 forever, 1 writes no loop extension), the same meaning the frame reader reports.
Input is 1 (grey), 3 (RGB) or 4 (RGBA) channels of 8 bits. The quantizer's quality and the encoder's speed are not tuned yet: a benchmark and quality gate come separately.
Decisions
The specification leaves these to the decoder; they are made as browsers make them.
| Case | Decoded as |
|---|---|
| Canvas before the first frame, disposal to background | Transparent black; the background colour index is not used. An opaque GIF (every frame covers the canvas, none has a transparent index) uses opaque black and decodes as RGB |
| Disposal methods 4–7 (undefined) | 1, do not dispose |
| An image extending past the canvas | Clipped |
| A logical screen of zero width or height | The images' bounding box |
| No colour table, or an index past the table | Opaque black |
| Image data cut off, or an undefined LZW code | Drawn as far as the data goes; the rest of the image keeps the canvas |
| The file ends early, or an unknown block | The images read so far; a file with no image is refused |
| A full LZW table without a clear code | Decoding continues with the table frozen |
| Frame delay | As stored (centiseconds), including 0: a viewer that plays 0 as 100 ms decides that itself |
| Loop count | NETSCAPE2.0 counts repetitions after the first play: a stored n plays n + 1 times (the frame reader's LoopCount; GifInfo.LoopCount is the stored value), 0 forever; an animation without it plays once |
Canvases and images above 2^26 pixels are refused, to bound what a decode allocates.
LINQPad samples
The package ships two runnable samples in linqpad-samples/:
decode: reads a real animated GIF, displays its metadata and first frame, then composites frames one at a time into a reused RGBA buffer.encode: creates a small RGBA animation, compares palette quantization with and without dithering, and decodes the result back for display.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Sdcb.SimdCodecs.Abstractions (>= 1.2.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Sdcb.SimdCodecs.Gif:
| Package | Downloads |
|---|---|
|
Sdcb.SimdCodecs
Image-codec facade over the Sdcb.SimdCodecs family: sniff a byte stream's format by its magic-byte signature and dispatch to the matching decoder (PNG, JPEG, TIFF, JBIG2, JPEG 2000, WebP, GIF, BMP, ICO, CUR, QOI, PBM / PGM / PPM / PAM, PFM), returning a codec-neutral IDecodedImage (fidelity tier: native bit depth + ColorEncoding colour signalling, with a ToFloats() RGBA float32 view) or decoding zero-copy into a caller-provided 8-bit RGBA buffer (display tier, integer-sample formats). AOT-compatible. |
GitHub repositories
This package is not used by any popular GitHub repositories.