public static GifEncoder CreateEncoder(string fileName, int width, int height, ImageHandlerConfig config) { switch (config.GifEncoder.Value) { default: case 0: { var enc = new BuildInGifEncoder(fileName, width, height); return(enc); } case 1: { var enc = new IndexGifEncoder(fileName, width, height); return(enc); } case 2: { var enc = new BuildInApngEncoder(fileName, width, height); enc.OptimizeEnabled = config.PaletteOptimized; return(enc); } } }
public void SaveAsGif(AnimationItem aniItem, string fileName, ImageHandlerConfig config) { //保存动画 天坑代码 var rec = new AnimationRecoder(this.GraphicsDevice); rec.Items.Add(aniItem); int length = rec.GetMaxLength(); //rec.GetGifTimeLine(30); 放弃获取时间轴 //预判大小阶段 rec.ResetAll(); Microsoft.Xna.Framework.Rectangle?bounds = null; int delay = Math.Max(10, config.MinDelay); for (int d = 0; d <= length; d += delay) { rec.Update(TimeSpan.FromMilliseconds(delay)); var rect = aniItem.Measure(); rect.Offset(aniItem.Position); bounds = (bounds == null || bounds.Value.IsEmpty) ? rect : Microsoft.Xna.Framework.Rectangle.Union(rect, bounds.Value); } //绘制阶段 rec.ResetAll(); switch (config.BackgroundType.Value) { default: case ImageBackgroundType.Transparent: rec.BackgroundColor = Color.TransparentBlack; break; case ImageBackgroundType.Color: rec.BackgroundColor = System.Drawing.Color.FromArgb(255, config.BackgroundColor.Value).ToXnaColor(); break; case ImageBackgroundType.Mosaic: rec.BackgroundImage = MonogameUtils.CreateMosaic(GraphicsDevice, config.MosaicInfo.Color0.ToXnaColor(), config.MosaicInfo.Color1.ToXnaColor(), Math.Max(1, config.MosaicInfo.BlockSize)); break; } byte[] buffer = new byte[bounds.Value.Width * bounds.Value.Height * 4]; byte[] bufferPrev = null, bufferGif = null; int gifTime = 0, prevTime = 0; string dirName = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".frames"); if (config.SavePngFramesEnabled && !Directory.Exists(dirName)) { Directory.CreateDirectory(dirName); } //选择encoder GifEncoder enc; switch (config.GifEncoder.Value) { default: case 0: enc = new BuildInGifEncoder(fileName, bounds.Value.Width, bounds.Value.Height); break; case 1: enc = new IndexGifEncoder(fileName, bounds.Value.Width, bounds.Value.Height); break; } Action <int> writeFrame = (curTime) => { unsafe { string pngFileName = Path.Combine(dirName, prevTime + ".png"); fixed(byte *pBuffer = bufferPrev, pBufferGif = bufferGif) { using (var bmp = new System.Drawing.Bitmap(bounds.Value.Width, bounds.Value.Height, bounds.Value.Width * 4, System.Drawing.Imaging.PixelFormat.Format32bppArgb, new IntPtr(pBuffer))) { var tasks = new List <Task>(); if (config.SavePngFramesEnabled) //保存单帧图像 { tasks.Add(Task.Factory.StartNew( () => bmp.Save(pngFileName, System.Drawing.Imaging.ImageFormat.Png) )); } //保存gif帧 int frameDelay = curTime - gifTime; frameDelay = (int)(Math.Round(frameDelay / 10.0) * 10); if (frameDelay > 0) { gifTime += frameDelay; var pData = new IntPtr(pBufferGif); tasks.Add(Task.Factory.StartNew(() => enc.AppendFrame(pData, frameDelay) )); } Task.WaitAll(tasks.ToArray()); } } } }; rec.Begin(bounds.Value); //0长度补丁 for (int d = 0; d <= length; d += delay, rec.Update(TimeSpan.FromMilliseconds(delay))) { rec.Draw(); using (var rt = rec.GetPngTexture()) { rt.GetData(buffer); //比较上一帧 if (bufferPrev != null) { //跳过当前帧 if (memcmp(buffer, bufferPrev, (IntPtr)buffer.Length) == 0) { continue; } else //计算时间 输出 { writeFrame(d); } } else { bufferPrev = new byte[bounds.Value.Width * bounds.Value.Height * 4]; } //交换缓冲区 var temp = buffer; buffer = bufferPrev; bufferPrev = temp; prevTime = d; //透明 额外导出一份gif if (config.BackgroundType.Value == ImageBackgroundType.Transparent) { using (var rt2 = rec.GetGifTexture(config.BackgroundColor.Value.ToXnaColor(), config.MinMixedAlpha)) { if (bufferGif == null) { bufferGif = new byte[bufferPrev.Length]; } rt2.GetData(bufferGif); } } else { bufferGif = bufferPrev; } } } //输出最后一帧 if (prevTime < length) { writeFrame(length); } else if (length <= 0) //0长度补丁 { writeFrame(100); } //保存动画长度 if (config.SavePngFramesEnabled) { File.WriteAllText(Path.Combine(dirName, "delay.txt"), length.ToString()); } rec.End(); enc.Dispose(); }