示例#1
0
        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();
        }