Exemple #1
0
        public static byte[] EncodeParallelExample(Gif gif)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var encodeProgress = new EncodeProgress();

            gif.EncodeParallel(progress =>
            {
                Console.WriteLine("Encode progress: {0}/{1}", progress.Progress, progress.FrameCount);
                encodeProgress = progress;
            });

            while (!encodeProgress.Completed)
            {
                Thread.Sleep(100);
            }

            if (encodeProgress.Exception != null)
            {
                throw encodeProgress.Exception;
            }

            stopwatch.Stop();

            Console.WriteLine("GIF encoded in {0:n2}s to binary.", stopwatch.Elapsed.TotalSeconds);

            return(encodeProgress.Bytes);
        }
Exemple #2
0
        /// <summary>
        /// Encode GIF in multiple threads.
        /// </summary>
        public void EncodeParallel(Action <EncodeProgress> onProgress, int scale = 1)        // TODO: Refact.
        {
            if (_free)
            {
                throw new Exception("The Free version doesn't support this feature. Please consider buying the Full version of Power GIF.");
            }

            const string header               = "GIF89a";
            var          width                = (ushort)(Frames[0].Texture.width * scale);
            var          height               = (ushort)(Frames[0].Texture.height * scale);
            var          globalColorTable     = new List <Color32>();
            var          applicationExtension = new ApplicationExtension();
            var          encoded              = new Dictionary <int, List <byte> >();
            var          encodeProgress       = new EncodeProgress {
                FrameCount = Frames.Count
            };
            var colorTables      = new List <Color32> [Frames.Count];
            var distinctColors   = new Dictionary <int, List <Color32> >();
            var manualResetEvent = new ManualResetEvent(false);

            for (var i = 0; i < Frames.Count; i++)
            {
                var frame = Frames[i];

                ThreadPool.QueueUserWorkItem(context =>
                {
                    var distinct = frame.Texture.GetPixels32().Distinct().ToList();

                    lock (distinctColors)
                    {
                        distinctColors.Add((int)context, distinct);

                        if (distinctColors.Count == Frames.Count)
                        {
                            manualResetEvent.Set();
                        }
                    }
                }, i);
            }

            manualResetEvent.WaitOne();

            for (var i = 0; i < Frames.Count; i++)
            {
                var colors = distinctColors[i];
                var add    = colors.Where(j => !globalColorTable.Contains(j)).ToList();

                if (globalColorTable.Count + add.Count <= 256)
                {
                    globalColorTable.AddRange(add);
                    colorTables[i] = globalColorTable;
                }
                else if (colors.Count <= 256)                 // Introduce local color table.
                {
                    colorTables[i] = colors;
                }
                else
                {
                    onProgress(new EncodeProgress {
                        Completed = true, Exception = new Exception($"Frame #{i} contains more than 256 colors!")
                    });
                    return;
                }
            }

            ReplaceTransparentColor(ref globalColorTable);

            for (var i = 0; i < Frames.Count; i++)             // Don't use Parallel.For to leave .NET compatibility.
            {
                ThreadPool.QueueUserWorkItem(context =>
                {
                    var index                 = (int)context;
                    var colorTable            = colorTables[index];
                    var localColorTableFlag   = (byte)(colorTable == globalColorTable ? 0 : 1);
                    var localColorTableSize   = GetColorTableSize(colorTable);
                    byte transparentColorFlag = 0, transparentColorIndex = 0;
                    byte max;
                    var colorIndexes            = GetColorIndexes(Frames[index].Texture, scale, colorTable, localColorTableFlag, ref transparentColorFlag, ref transparentColorIndex, out max);
                    var graphicControlExtension = new GraphicControlExtension(4, 0, (byte)Frames[index].DisposalMethod, 0, transparentColorFlag, (ushort)(100 * Frames[index].Delay), transparentColorIndex);
                    var imageDescriptor         = new ImageDescriptor(0, 0, width, height, localColorTableFlag, 0, 0, 0, localColorTableSize);
                    var minCodeSize             = LzwEncoder.GetMinCodeSize(max);
                    var lzw = LzwEncoder.Encode(colorIndexes, minCodeSize);
                    var tableBasedImageData = new TableBasedImageData(minCodeSize, lzw);
                    var bytes = new List <byte>();

                    bytes.AddRange(graphicControlExtension.GetBytes());
                    bytes.AddRange(imageDescriptor.GetBytes());

                    if (localColorTableFlag == 1)
                    {
                        bytes.AddRange(ColorTableToBytes(colorTable, localColorTableSize));
                    }

                    bytes.AddRange(tableBasedImageData.GetBytes());

                    lock (encoded)
                    {
                        encoded.Add(index, bytes);
                        encodeProgress.Progress++;

                        if (encoded.Count == Frames.Count)
                        {
                            var globalColorTableSize    = GetColorTableSize(globalColorTable);
                            var logicalScreenDescriptor = new LogicalScreenDescriptor(width, height, 1, 7, 0, globalColorTableSize, 0, 0);
                            var binary = new List <byte>();

                            binary.AddRange(Encoding.UTF8.GetBytes(header));
                            binary.AddRange(logicalScreenDescriptor.GetBytes());
                            binary.AddRange(ColorTableToBytes(globalColorTable, globalColorTableSize));
                            binary.AddRange(applicationExtension.GetBytes());
                            binary.AddRange(encoded.OrderBy(j => j.Key).SelectMany(j => j.Value));
                            binary.Add(0x3B);                         // GIF Trailer.

                            encodeProgress.Bytes     = binary.ToArray();
                            encodeProgress.Completed = true;
                        }

                        onProgress(encodeProgress);
                    }
                }, i);
            }
        }