Load the GIF, call Resize and save it as a GIF. Every operation applies to every frame, so the frames, their delays and the loop setting come through with no extra code. The program below halves a 44-frame GIF of the rotating Earth from Wikimedia Commons (CC BY-SA 3.0).
dotnet new console -o ResizeGif && cd ResizeGif dotnet add package RecursiveAI.OneImage --version 1.10.4 curl -L -o earth.gif \ "https://commons.wikimedia.org/wiki/Special:FilePath/Rotating_earth_(large).gif"
OneImage needs the .NET 10 SDK. Put this in Program.cs and run dotnet run:
using OneImage; Image gif = Image.Load("earth.gif"); Console.WriteLine($"earth.gif: {gif.Width}x{gif.Height}, {gif.FrameCount} frames, " + $"{gif.Frames[0].Delay.TotalMilliseconds} ms each"); // Every frame is resized; delays and the loop count are kept. gif.Resize(width: 200).Save("earth-200.gif"); Image small = Image.Load("earth-200.gif"); Console.WriteLine($"earth-200.gif: {small.Width}x{small.Height}, " + $"{small.FrameCount} frames, " + $"{small.Frames[0].Delay.TotalMilliseconds} ms each");
earth.gif: 400x400, 44 frames, 90 ms each earth-200.gif: 200x200, 44 frames, 90 ms each
Frames come out composited: each is the full picture at that moment, with the GIF’s disposal and transparency rules applied, which is why one Resize call is enough. The same holds for Crop, Rotate, color changes and watermarks. Fit modes work too, such as Resize(width: 200, height: 200, fit: Fit.Cover) for a square.
A still preview, and a smaller file
Frames[i].ToImage() turns one frame into an ordinary image. Animated WebP is usually far smaller than GIF and plays in current browsers:
using OneImage; Image gif = Image.Load("earth.gif").Resize(width: 200); // The first frame as a plain PNG. Saving the whole animation to .png // would write an animated PNG. gif.Frames[0].ToImage().Save("poster.png"); gif.Save("earth-200.webp"); gif.Save("earth-200-64.gif", new SaveOptions { EncoderOptions = new GifEncoderOptions { MaxColors = 64 }, }); foreach (string file in new[] { "earth.gif", "earth-200.gif", "earth-200-64.gif", "earth-200.webp", "poster.png" }) { ImageInfo info = Image.Identify(file); long kb = new FileInfo(file).Length / 1024; Console.WriteLine($"{file}: {info.Frames.Count} frame(s), {kb} KB"); }
earth.gif: 44 frame(s), 978 KB earth-200.gif: 44 frame(s), 453 KB earth-200-64.gif: 44 frame(s), 318 KB earth-200.webp: 44 frame(s), 98 KB poster.png: 1 frame(s), 43 KB
To get every frame as a file, loop over Frames and save each ToImage().
Limits
- JPEG and BMP hold one image. Saving an animation to
.jpgwrites the first frame only. GIF, WebP, PNG (APNG) and TIFF keep every frame. - Each frame is re-quantized to a palette of at most 256 colors, so a resized GIF is smaller but not proportionally: expect about half, not a quarter.
- At most 1,000 frames load by default; raise
LoadOptions.Limitsif you need more.
To watermark every frame, see Add a watermark; for WebP settings, Convert an image to WebP. Animation is covered in the guide.