如何在C#中将.gif文件转换为.ani文件并保留所有帧
在C#中将GIF动画转换为ANI并保留所有帧
要实现GIF到ANI的完整帧转换,核心是解析GIF的帧数据与动画参数,再按照ANI文件的规范重新封装这些内容。以下是具体实现步骤和代码示例:
核心前提
ANI是Windows动画光标格式,由多个ICO帧、延迟时间、循环设置组成。要完整保留GIF帧,需确保:
- 提取GIF的每帧图像(包括透明通道)
- 转换GIF的帧延迟(百分之一秒)为ANI的毫秒延迟
- 继承GIF的循环设置(无限循环或指定次数)
实现步骤(使用ImageSharp跨平台库)
1. 安装依赖
在项目中安装SixLabors.ImageSharp和SixLabors.ImageSharp.Formats.Gif包:
dotnet add package SixLabors.ImageSharp dotnet add package SixLabors.ImageSharp.Formats.Gif
2. 读取GIF的帧与动画参数
using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; // 读取GIF文件 var gifPath = "input.gif"; using var gifImage = Image.Load<Rgba32>(gifPath, out var gifDecoder); var gifMetadata = gifImage.Metadata.GetGifMetadata(); // 提取所有帧及延迟时间(GIF延迟单位为1/100秒,需转为毫秒) var frames = new List<(Image<Rgba32> Frame, int DelayMs)>(); foreach (var frame in gifImage.Frames) { var frameMetadata = frame.Metadata.GetGifMetadata(); int delayMs = frameMetadata.DelayTime * 10; // 转换为毫秒 frames.Add((frame.Clone(), delayMs)); } // 获取循环次数:0表示无限循环 int loopCount = gifMetadata.RepeatCount;
3. 构建并写入ANI文件
ANI文件的结构包含ACON主块、LIST帧列表块,以及每个帧的ICON数据。以下是简化的写入实现:
using System.IO; using System.Buffers.Binary; // 定义ANI头结构(简化版) struct AniHeader { public uint Signature; // "RIFF" public uint FileSize; public uint AniSignature; // "ACON" public uint ListSignature; // "LIST" public uint ListSize; public uint InfoSignature; // "INFO" public uint InfoSize; public ushort Version; public ushort Flags; public ushort NumFrames; public ushort NumSteps; public ushort Width; public ushort Height; public ushort BitCount; public ushort Planes; public int DisplayRate; // 单帧延迟,若各帧延迟不同需扩展FRAM块 public int LoopCount; } // 写入ANI文件 var aniPath = "output.ani"; using var fs = new FileStream(aniPath, FileMode.Create); using var writer = new BinaryWriter(fs); // 计算基本参数 int frameCount = frames.Count; var firstFrame = frames[0].Frame; ushort width = (ushort)firstFrame.Width; ushort height = (ushort)firstFrame.Height; // 构建ANI头 var header = new AniHeader { Signature = BinaryPrimitives.ReadUInt32LittleEndian(System.Text.Encoding.ASCII.GetBytes("RIFF")), FileSize = 0, // 后续计算 AniSignature = BinaryPrimitives.ReadUInt32LittleEndian(System.Text.Encoding.ASCII.GetBytes("ACON")), ListSignature = BinaryPrimitives.ReadUInt32LittleEndian(System.Text.Encoding.ASCII.GetBytes("LIST")), ListSize = 0, // 后续计算 InfoSignature = BinaryPrimitives.ReadUInt32LittleEndian(System.Text.Encoding.ASCII.GetBytes("INFO")), InfoSize = 36, Version = 0x0001, Flags = 0, NumFrames = (ushort)frameCount, NumSteps = (ushort)frameCount, Width = width, Height = height, BitCount = 32, // 保留32位透明通道 Planes = 1, DisplayRate = frames[0].DelayMs, // 若各帧延迟不同,需单独处理FRAM块 LoopCount = loopCount == 0 ? -1 : loopCount // ANI中-1表示无限循环 }; // 先写入头占位 writer.Write(header.Signature); writer.Write(header.FileSize); writer.Write(header.AniSignature); writer.Write(header.ListSignature); writer.Write(header.ListSize); writer.Write(header.InfoSignature); writer.Write(header.InfoSize); writer.Write(header.Version); writer.Write(header.Flags); writer.Write(header.NumFrames); writer.Write(header.NumSteps); writer.Write(header.Width); writer.Write(header.Height); writer.Write(header.BitCount); writer.Write(header.Planes); writer.Write(header.DisplayRate); writer.Write(header.LoopCount); // 写入每个帧的ICO数据 long listStartPos = fs.Position - 4; // 记录LIST块位置,后续更新大小 foreach (var (frame, delay) in frames) { // 将帧保存为ICO格式到内存流 using var icoStream = new MemoryStream(); frame.SaveAsIco(icoStream); icoStream.Seek(0, SeekOrigin.Begin); // 写入ICO数据到ANI icoStream.CopyTo(fs); } // 更新LIST块大小和文件总大小 long endPos = fs.Position; long listSize = endPos - listStartPos - 4; fs.Seek(listStartPos, SeekOrigin.Begin); writer.Write((uint)listSize); long fileSize = endPos - 8; // 减去RIFF的8字节 fs.Seek(4, SeekOrigin.Begin); writer.Write((uint)fileSize);
关键注意事项
- 延迟时间处理:GIF的延迟是每100分之一秒,需乘以10转为ANI的毫秒单位;若GIF各帧延迟不同,需为每个帧添加
FRAM块单独指定延迟。 - 透明通道保留:确保使用支持RGBA的图像库(如ImageSharp),避免丢失GIF的透明信息。
- 跨平台兼容:若使用.NET Framework,也可以用
System.Drawing读取GIF,但需注意GDI+在非Windows平台的限制。
内容的提问来源于stack exchange,提问作者Little Boy Blue
相关产品推荐
相关产品推荐

