Esempio n. 1
0
        private async void Encode(List <FrameInfo> listFrames, int id, Parameters param, CancellationTokenSource tokenSource)
        {
            var processing = this.DispatcherStringResource("Encoder.Processing");

            try
            {
                switch (param.Type)
                {
                case Export.Gif:

                    #region Gif

                    #region Cut/Paint Unchanged Pixels

                    if (param.EncoderType == GifEncoderType.Legacy || param.EncoderType == GifEncoderType.ScreenToGif)
                    {
                        if (param.DetectUnchangedPixels)
                        {
                            Update(id, 0, FindResource("Encoder.Analyzing").ToString());

                            if (param.DummyColor.HasValue)
                            {
                                var color = Color.FromArgb(param.DummyColor.Value.R, param.DummyColor.Value.G, param.DummyColor.Value.B);

                                listFrames = ImageMethods.PaintTransparentAndCut(listFrames, color, id, tokenSource);
                            }
                            else
                            {
                                listFrames = ImageMethods.CutUnchanged(listFrames, id, tokenSource);
                            }
                        }
                        else
                        {
                            var size = listFrames[0].Path.ScaledSize();
                            listFrames.ForEach(x => x.Rect = new Int32Rect(0, 0, (int)size.Width, (int)size.Height));
                        }
                    }

                    #endregion

                    switch (param.EncoderType)
                    {
                    case GifEncoderType.ScreenToGif:

                        #region Improved encoding

                        using (var stream = new MemoryStream())
                        {
                            using (var encoder = new GifFile(stream, param.RepeatCount))
                            {
                                encoder.UseGlobalColorTable = param.UseGlobalColorTable;
                                encoder.TransparentColor    = param.DummyColor;
                                encoder.MaximumNumberColor  = param.MaximumNumberColors;

                                for (var i = 0; i < listFrames.Count; i++)
                                {
                                    if (!listFrames[i].HasArea && param.DetectUnchangedPixels)
                                    {
                                        continue;
                                    }

                                    if (listFrames[i].Delay == 0)
                                    {
                                        listFrames[i].Delay = 10;
                                    }

                                    encoder.AddFrame(listFrames[i].Path, listFrames[i].Rect, listFrames[i].Delay);

                                    Update(id, i, string.Format(processing, i));

                                    #region Cancellation

                                    if (tokenSource.Token.IsCancellationRequested)
                                    {
                                        SetStatus(Status.Canceled, id);
                                        break;
                                    }

                                    #endregion
                                }
                            }

                            try
                            {
                                using (var fileStream = new FileStream(param.Filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096))
                                    stream.WriteTo(fileStream);
                            }
                            catch (Exception ex)
                            {
                                SetStatus(Status.Error, id);
                                LogWriter.Log(ex, "Improved Encoding");
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.Legacy:

                        #region Legacy Encoding

                        using (var encoder = new AnimatedGifEncoder())
                        {
                            if (param.DummyColor.HasValue)
                            {
                                var color = Color.FromArgb(param.DummyColor.Value.R,
                                                           param.DummyColor.Value.G, param.DummyColor.Value.B);

                                encoder.SetTransparent(color);
                                encoder.SetDispose(1);         //Undraw Method, "Leave".
                            }

                            encoder.Start(param.Filename);
                            encoder.SetQuality(param.Quality);
                            encoder.SetRepeat(param.RepeatCount);

                            var numImage = 0;
                            foreach (var frame in listFrames)
                            {
                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion

                                if (!frame.HasArea && param.DetectUnchangedPixels)
                                {
                                    continue;
                                }

                                var bitmapAux = new Bitmap(frame.Path);

                                encoder.SetDelay(frame.Delay);
                                encoder.AddFrame(bitmapAux, frame.Rect.X, frame.Rect.Y);

                                bitmapAux.Dispose();

                                Update(id, numImage, string.Format(processing, numImage));
                                numImage++;
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.PaintNet:

                        #region paint.NET encoding

                        using (var stream = new MemoryStream())
                        {
                            using (var encoder = new GifEncoder(stream, null, null, param.RepeatCount))
                            {
                                for (var i = 0; i < listFrames.Count; i++)
                                {
                                    var bitmapAux = new Bitmap(listFrames[i].Path);
                                    encoder.AddFrame(bitmapAux, 0, 0, TimeSpan.FromMilliseconds(listFrames[i].Delay));
                                    bitmapAux.Dispose();

                                    Update(id, i, string.Format(processing, i));

                                    #region Cancellation

                                    if (tokenSource.Token.IsCancellationRequested)
                                    {
                                        SetStatus(Status.Canceled, id);

                                        break;
                                    }

                                    #endregion
                                }
                            }

                            stream.Position = 0;

                            try
                            {
                                using (var fileStream = new FileStream(param.Filename, FileMode.Create, FileAccess.Write, FileShare.None, Constants.BufferSize, false))
                                    stream.WriteTo(fileStream);
                            }
                            catch (Exception ex)
                            {
                                SetStatus(Status.Error, id);
                                LogWriter.Log(ex, "Encoding with paint.Net.");
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.FFmpeg:

                        #region FFmpeg encoding

                        SetStatus(Status.Processing, id, null, true);

                        if (!Util.Other.IsFfmpegPresent())
                        {
                            throw new ApplicationException("FFmpeg not present.");
                        }

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        #region Generate concat

                        var concat = new StringBuilder();
                        foreach (var frame in listFrames)
                        {
                            concat.AppendLine("file '" + frame.Path + "'");
                            concat.AppendLine("duration " + (frame.Delay / 1000d).ToString(CultureInfo.InvariantCulture));
                        }

                        var concatPath = Path.GetDirectoryName(listFrames[0].Path) ?? Path.GetTempPath();
                        var concatFile = Path.Combine(concatPath, "concat.txt");

                        if (!Directory.Exists(concatPath))
                        {
                            Directory.CreateDirectory(concatPath);
                        }

                        if (File.Exists(concatFile))
                        {
                            File.Delete(concatFile);
                        }

                        File.WriteAllText(concatFile, concat.ToString());

                        #endregion

                        param.Command = string.Format(param.Command, concatFile, param.ExtraParameters.Replace("{H}", param.Height.ToString()).Replace("{W}", param.Width.ToString()), param.Filename);

                        var process = new ProcessStartInfo(UserSettings.All.FfmpegLocation)
                        {
                            Arguments             = param.Command,
                            CreateNoWindow        = true,
                            ErrorDialog           = false,
                            UseShellExecute       = false,
                            RedirectStandardError = true
                        };

                        var pro = Process.Start(process);

                        var str = pro.StandardError.ReadToEnd();

                        var fileInfo = new FileInfo(param.Filename);

                        if (!fileInfo.Exists || fileInfo.Length == 0)
                        {
                            throw new Exception("Error while encoding the gif with FFmpeg.")
                                  {
                                      HelpLink = $"Command:\n\r{param.Command}\n\rResult:\n\r{str}"
                                  }
                        }
                        ;

                        #endregion

                        break;

                    case GifEncoderType.Gifski:

                        #region Gifski encoding

                        SetStatus(Status.Processing, id, null, true);

                        if (!Util.Other.IsGifskiPresent())
                        {
                            throw new ApplicationException("Gifski not present.");
                        }

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        var gifski = new GifskiInterop();
                        var handle = gifski.Start(UserSettings.All.GifskiQuality, UserSettings.All.Looped);

                        ThreadPool.QueueUserWorkItem(delegate
                        {
                            Thread.Sleep(500);
                            SetStatus(Status.Processing, id, null, false);

                            for (var i = 0; i < listFrames.Count; i++)
                            {
                                Update(id, i, string.Format(processing, i));
                                gifski.AddFrame(handle, (uint)i, listFrames[i].Path, listFrames[i].Delay);
                            }

                            gifski.EndAdding(handle);
                        }, null);

                        gifski.End(handle, param.Filename);

                        var fileInfo2 = new FileInfo(param.Filename);

                        if (!fileInfo2.Exists || fileInfo2.Length == 0)
                        {
                            throw new Exception("Error while encoding the gif with Gifski.", new Win32Exception())
                                  {
                                      HelpLink = $"Command:\n\r{param.Command}\n\rResult:\n\r{Marshal.GetLastWin32Error()}"
                                  }
                        }
                        ;

                        #endregion

                        break;

                    default:
                        throw new Exception("Undefined Gif encoder type");
                    }

                    #endregion

                    break;

                case Export.Apng:

                    #region Apng

                    #region Cut/Paint Unchanged Pixels

                    if (param.DetectUnchangedPixels)
                    {
                        Update(id, 0, FindResource("Encoder.Analyzing").ToString());

                        if (param.DummyColor.HasValue)
                        {
                            var color = Color.FromArgb(param.DummyColor.Value.A, param.DummyColor.Value.R, param.DummyColor.Value.G, param.DummyColor.Value.B);
                            listFrames = ImageMethods.PaintTransparentAndCut(listFrames, color, id, tokenSource);
                        }
                        else
                        {
                            listFrames = ImageMethods.CutUnchanged(listFrames, id, tokenSource);
                        }
                    }
                    else
                    {
                        var size = listFrames[0].Path.ScaledSize();
                        listFrames.ForEach(x => x.Rect = new Int32Rect(0, 0, (int)size.Width, (int)size.Height));
                    }

                    #endregion

                    #region Encoding

                    using (var stream = new MemoryStream())
                    {
                        var frameCount = listFrames.Count(x => x.HasArea);

                        using (var encoder = new Apng(stream, frameCount, param.RepeatCount))
                        {
                            for (var i = 0; i < listFrames.Count; i++)
                            {
                                if (!listFrames[i].HasArea && param.DetectUnchangedPixels)
                                {
                                    continue;
                                }

                                if (listFrames[i].Delay == 0)
                                {
                                    listFrames[i].Delay = 10;
                                }

                                encoder.AddFrame(listFrames[i].Path, listFrames[i].Rect, listFrames[i].Delay);

                                Update(id, i, string.Format(processing, i));

                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion
                            }
                        }

                        try
                        {
                            using (var fileStream = new FileStream(param.Filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096))
                                stream.WriteTo(fileStream);
                        }
                        catch (Exception ex)
                        {
                            SetStatus(Status.Error, id);
                            LogWriter.Log(ex, "Apng Encoding");
                        }
                    }

                    #endregion

                    #endregion

                    break;

                case Export.Video:

                    #region Video

                    switch (param.VideoEncoder)
                    {
                    case VideoEncoderType.AviStandalone:

                        #region Avi Standalone

                        var image = listFrames[0].Path.SourceFrom();

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        //1000 / listFrames[0].Delay
                        using (var aviWriter = new AviWriter(param.Filename, param.Framerate, image.PixelWidth, image.PixelHeight, param.VideoQuality))
                        {
                            var numImage = 0;
                            foreach (var frame in listFrames)
                            {
                                using (var outStream = new MemoryStream())
                                {
                                    var bitImage = frame.Path.SourceFrom();

                                    var enc = new BmpBitmapEncoder();
                                    enc.Frames.Add(BitmapFrame.Create(bitImage));
                                    enc.Save(outStream);

                                    outStream.Flush();

                                    using (var bitmap = new Bitmap(outStream))
                                        aviWriter.AddFrame(bitmap, param.FlipVideo);
                                }

                                Update(id, numImage, string.Format(processing, numImage));
                                numImage++;

                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion
                            }
                        }

                        #endregion

                        break;

                    case VideoEncoderType.Ffmpg:

                        #region Video using FFmpeg

                        SetStatus(Status.Processing, id, null, true);

                        if (!Util.Other.IsFfmpegPresent())
                        {
                            throw new ApplicationException("FFmpeg not present.");
                        }

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        #region Generate concat

                        var concat = new StringBuilder();
                        foreach (var frame in listFrames)
                        {
                            concat.AppendLine("file '" + frame.Path + "'");
                            concat.AppendLine("duration " + (frame.Delay / 1000d).ToString(CultureInfo.InvariantCulture));
                        }

                        var concatPath = Path.GetDirectoryName(listFrames[0].Path) ?? Path.GetTempPath();
                        var concatFile = Path.Combine(concatPath, "concat.txt");

                        if (!Directory.Exists(concatPath))
                        {
                            Directory.CreateDirectory(concatPath);
                        }

                        if (File.Exists(concatFile))
                        {
                            File.Delete(concatFile);
                        }

                        File.WriteAllText(concatFile, concat.ToString());

                        #endregion

                        param.Command = string.Format(param.Command, concatFile, param.ExtraParameters.Replace("{H}", param.Height.ToString()).Replace("{W}", param.Width.ToString()), param.Filename);

                        var process = new ProcessStartInfo(UserSettings.All.FfmpegLocation)
                        {
                            Arguments             = param.Command,
                            CreateNoWindow        = true,
                            ErrorDialog           = false,
                            UseShellExecute       = false,
                            RedirectStandardError = true
                        };

                        var pro = Process.Start(process);

                        var str = pro.StandardError.ReadToEnd();

                        var fileInfo = new FileInfo(param.Filename);

                        if (!fileInfo.Exists || fileInfo.Length == 0)
                        {
                            throw new Exception("Error while encoding with FFmpeg.")
                                  {
                                      HelpLink = str
                                  }
                        }
                        ;

                        #endregion

                        break;

                    default:
                        throw new Exception("Undefined video encoder");
                    }

                    #endregion

                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(param));
                }

                //If it was canceled, try deleting the file.
                if (tokenSource.Token.IsCancellationRequested)
                {
                    if (File.Exists(param.Filename))
                    {
                        File.Delete(param.Filename);
                    }

                    SetStatus(Status.Canceled, id);
                    return;
                }

                #region Upload

                if (param.Upload && File.Exists(param.Filename))
                {
                    InternalUpdate(id, "Encoder.Uploading", true, true);

                    try
                    {
                        ICloud cloud = CloudFactory.CreateCloud(param.UploadDestinationIndex);

                        var uploadedFile = await cloud.UploadFileAsync(param.Filename, CancellationToken.None);

                        InternalSetUpload(id, true, uploadedFile.Link, uploadedFile.DeleteLink);
                    }
                    catch (Exception e)
                    {
                        LogWriter.Log(e, "It was not possible to run the post encoding command.");
                        InternalSetUpload(id, false, null, null, e);
                    }
                }

                #endregion

                #region Copy to clipboard

                if (param.CopyToClipboard && File.Exists(param.Filename))
                {
                    Dispatcher.Invoke(() =>
                    {
                        try
                        {
                            var data = new DataObject();

                            switch (param.CopyType)
                            {
                            case CopyType.File:
                                if (param.Type != Export.Video)
                                {
                                    data.SetImage(param.Filename.SourceFrom());
                                }

                                data.SetText(param.Filename, TextDataFormat.Text);
                                data.SetFileDropList(new StringCollection {
                                    param.Filename
                                });
                                break;

                            case CopyType.FolderPath:
                                data.SetText(Path.GetDirectoryName(param.Filename) ?? param.Filename, TextDataFormat.Text);
                                break;

                            case CopyType.Link:
                                var link = InternalGetUpload(id);

                                data.SetText(string.IsNullOrEmpty(link) ? param.Filename : link, TextDataFormat.Text);
                                break;

                            default:
                                data.SetText(param.Filename, TextDataFormat.Text);
                                break;
                            }

                            //It tries to set the data to the clipboard 10 times before failing it to do so.
                            //This issue may happen if the clipboard is opened by any clipboard manager.
                            for (var i = 0; i < 10; i++)
                            {
                                try
                                {
                                    Clipboard.SetDataObject(data, true);
                                    break;
                                }
                                catch (COMException ex)
                                {
                                    if ((uint)ex.ErrorCode != 0x800401D0) //CLIPBRD_E_CANT_OPEN
                                    {
                                        throw;
                                    }
                                }

                                Thread.Sleep(100);
                            }

                            InternalSetCopy(id, true);
                        }
                        catch (Exception e)
                        {
                            LogWriter.Log(e, "It was not possible to copy the file.");
                            InternalSetCopy(id, false, e);
                        }
                    });
                }

                #endregion

                #region Execute commands

                if (param.ExecuteCommands && !string.IsNullOrWhiteSpace(param.PostCommands))
                {
                    InternalUpdate(id, "Encoder.Executing", true, true);

                    var command = param.PostCommands.Replace("{p}", "\"" + param.Filename + "\"").Replace("{f}", "\"" + Path.GetDirectoryName(param.Filename) + "\"");
                    var output  = "";

                    try
                    {
                        foreach (var com in command.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            var procStartInfo = new ProcessStartInfo("cmd", "/c " + com)
                            {
                                RedirectStandardOutput = true,
                                RedirectStandardError  = true,
                                UseShellExecute        = false,
                                CreateNoWindow         = true
                            };

                            using (var process = new Process())
                            {
                                process.StartInfo = procStartInfo;
                                process.Start();

                                var message = process.StandardOutput.ReadToEnd();
                                var error   = process.StandardError.ReadToEnd();

                                if (!string.IsNullOrWhiteSpace(message))
                                {
                                    output += message + Environment.NewLine;
                                }

                                if (!string.IsNullOrWhiteSpace(message))
                                {
                                    output += message + Environment.NewLine;
                                }

                                if (!string.IsNullOrWhiteSpace(error))
                                {
                                    throw new Exception(error);
                                }

                                process.WaitForExit(1000);
                            }
                        }

                        InternalSetCommand(id, true, command, output);
                    }
                    catch (Exception e)
                    {
                        LogWriter.Log(e, "It was not possible to run the post encoding command.");
                        InternalSetCommand(id, false, command, output, e);
                    }
                }

                #endregion

                if (!tokenSource.Token.IsCancellationRequested)
                {
                    SetStatus(Status.Completed, id, param.Filename);
                }
            }
            catch (Exception ex)
            {
                LogWriter.Log(ex, "Encode");

                SetStatus(Status.Error, id, null, false, ex);
            }
            finally
            {
                #region Delete Encoder Folder

                try
                {
                    var encoderFolder = Path.GetDirectoryName(listFrames[0].Path);

                    if (!string.IsNullOrEmpty(encoderFolder))
                    {
                        if (Directory.Exists(encoderFolder))
                        {
                            Directory.Delete(encoderFolder, true);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogWriter.Log(ex, "Cleaning the Encode folder");
                }

                #endregion

                GC.Collect();
            }
        }
Esempio n. 2
0
        private void Encode(List <FrameInfo> listFrames, int id, Parameters param, CancellationTokenSource tokenSource)
        {
            var processing = FindResource("Encoder.Processing").ToString();

            try
            {
                switch (param.Type)
                {
                case Export.Gif:

                    #region Gif

                    var gifParam = (GifParameters)param;

                    #region Cut/Paint Unchanged Pixels

                    if (gifParam.DetectUnchangedPixels && (gifParam.EncoderType == GifEncoderType.Legacy || gifParam.EncoderType == GifEncoderType.ScreenToGif))
                    {
                        Update(id, 0, FindResource("Encoder.Analyzing").ToString());

                        if (gifParam.DummyColor.HasValue)
                        {
                            var color = Color.FromArgb(gifParam.DummyColor.Value.R, gifParam.DummyColor.Value.G, gifParam.DummyColor.Value.B);

                            listFrames = ImageMethods.PaintTransparentAndCut(listFrames, color, id, tokenSource);
                        }
                        else
                        {
                            listFrames = ImageMethods.CutUnchanged(listFrames, id, tokenSource);
                        }
                    }

                    #endregion

                    switch (gifParam.EncoderType)
                    {
                    case GifEncoderType.ScreenToGif:

                        #region Improved encoding

                        using (var stream = new MemoryStream())
                        {
                            using (var encoder = new GifFile(stream, gifParam.RepeatCount))
                            {
                                encoder.UseGlobalColorTable = gifParam.UseGlobalColorTable;
                                encoder.TransparentColor    = gifParam.DummyColor;
                                encoder.MaximumNumberColor  = gifParam.MaximumNumberColors;

                                for (var i = 0; i < listFrames.Count; i++)
                                {
                                    if (!listFrames[i].HasArea)
                                    {
                                        continue;
                                    }

                                    if (listFrames[i].Delay == 0)
                                    {
                                        listFrames[i].Delay = 10;
                                    }

                                    encoder.AddFrame(listFrames[i].ImageLocation, listFrames[i].Rect, listFrames[i].Delay);

                                    Update(id, i, string.Format(processing, i));

                                    #region Cancellation

                                    if (tokenSource.Token.IsCancellationRequested)
                                    {
                                        SetStatus(Status.Canceled, id);

                                        break;
                                    }

                                    #endregion
                                }
                            }

                            try
                            {
                                using (var fileStream = new FileStream(gifParam.Filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096))
                                {
                                    stream.WriteTo(fileStream);
                                }
                            }
                            catch (Exception ex)
                            {
                                SetStatus(Status.Error, id);
                                LogWriter.Log(ex, "Improved Encoding");
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.Legacy:

                        #region Legacy Encoding

                        using (var encoder = new AnimatedGifEncoder())
                        {
                            if (gifParam.DummyColor.HasValue)
                            {
                                var color = Color.FromArgb(gifParam.DummyColor.Value.R,
                                                           gifParam.DummyColor.Value.G, gifParam.DummyColor.Value.B);

                                encoder.SetTransparent(color);
                                encoder.SetDispose(1);         //Undraw Method, "Leave".
                            }

                            encoder.Start(gifParam.Filename);
                            encoder.SetQuality(gifParam.Quality);
                            encoder.SetRepeat(gifParam.RepeatCount);

                            var numImage = 0;
                            foreach (var frame in listFrames)
                            {
                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion

                                if (!frame.HasArea && gifParam.DetectUnchangedPixels)
                                {
                                    continue;
                                }

                                var bitmapAux = new Bitmap(frame.ImageLocation);

                                encoder.SetDelay(frame.Delay);
                                encoder.AddFrame(bitmapAux, frame.Rect.X, frame.Rect.Y);

                                bitmapAux.Dispose();

                                Update(id, numImage, string.Format(processing, numImage));
                                numImage++;
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.PaintNet:

                        #region paint.NET encoding

                        using (var stream = new MemoryStream())
                        {
                            using (var encoder = new GifEncoder(stream, null, null, gifParam.RepeatCount))
                            {
                                for (var i = 0; i < listFrames.Count; i++)
                                {
                                    var bitmapAux = new Bitmap(listFrames[i].ImageLocation);
                                    encoder.AddFrame(bitmapAux, 0, 0, TimeSpan.FromMilliseconds(listFrames[i].Delay));
                                    bitmapAux.Dispose();

                                    Update(id, i, string.Format(processing, i));

                                    #region Cancellation

                                    if (tokenSource.Token.IsCancellationRequested)
                                    {
                                        SetStatus(Status.Canceled, id);

                                        break;
                                    }

                                    #endregion
                                }
                            }

                            stream.Position = 0;

                            try
                            {
                                using (var fileStream = new FileStream(gifParam.Filename, FileMode.Create, FileAccess.Write, FileShare.None, Constants.BufferSize, false))
                                {
                                    stream.WriteTo(fileStream);
                                }
                            }
                            catch (Exception ex)
                            {
                                SetStatus(Status.Error, id);
                                LogWriter.Log(ex, "Encoding with paint.Net.");
                            }
                        }

                        #endregion

                        break;

                    default:
                        throw new Exception("Undefined Gif encoder type");
                    }

                    #endregion

                    break;

                case Export.Video:

                    #region Video

                    var videoParam = (VideoParameters)param;

                    switch (videoParam.VideoEncoder)
                    {
                    case VideoEncoderType.AviStandalone:

                        #region Avi Standalone

                        var image = listFrames[0].ImageLocation.SourceFrom();

                        using (var aviWriter = new AviWriter(videoParam.Filename, 1000 / listFrames[0].Delay, image.PixelWidth, image.PixelHeight, videoParam.Quality))
                        {
                            var numImage = 0;
                            foreach (var frame in listFrames)
                            {
                                using (var outStream = new MemoryStream())
                                {
                                    var bitImage = frame.ImageLocation.SourceFrom();

                                    var enc = new BmpBitmapEncoder();
                                    enc.Frames.Add(BitmapFrame.Create(bitImage));
                                    enc.Save(outStream);

                                    outStream.Flush();

                                    using (var bitmap = new Bitmap(outStream))
                                    {
                                        aviWriter.AddFrame(bitmap);
                                    }
                                }

                                //aviWriter.AddFrame(new BitmapImage(new Uri(frame.ImageLocation)));

                                Update(id, numImage, string.Format(processing, numImage));
                                numImage++;

                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion
                            }
                        }

                        #endregion

                        break;

                    case VideoEncoderType.Ffmpg:

                        #region Video using FFmpeg

                        SetStatus(Status.Encoding, id, null, true);

                        if (!Util.Other.IsFfmpegPresent())
                        {
                            throw new ApplicationException("FFmpeg not present.");
                        }

                        videoParam.Command = string.Format(videoParam.Command,
                                                           Path.Combine(Path.GetDirectoryName(listFrames[0].ImageLocation), "%d.png"),
                                                           videoParam.ExtraParameters, videoParam.Framerate,
                                                           param.Filename);

                        var process = new ProcessStartInfo(Settings.Default.FfmpegLocation)
                        {
                            Arguments             = videoParam.Command,
                            CreateNoWindow        = true,
                            ErrorDialog           = false,
                            UseShellExecute       = false,
                            RedirectStandardError = true
                        };

                        var pro = Process.Start(process);

                        var str = pro.StandardError.ReadToEnd();

                        var fileInfo = new FileInfo(param.Filename);

                        if (!fileInfo.Exists || fileInfo.Length == 0)
                        {
                            throw new Exception("Error while encoding with FFmpeg.", new Exception(str));
                        }

                        #endregion

                        break;

                    default:
                        throw new Exception("Undefined video encoder");
                    }

                    #endregion

                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(param));
                }

                if (!tokenSource.Token.IsCancellationRequested)
                {
                    SetStatus(Status.Completed, id, param.Filename);
                }
            }
            catch (Exception ex)
            {
                LogWriter.Log(ex, "Encode");

                SetStatus(Status.Error, id, null, false, ex.Message);
            }
            finally
            {
                #region Delete Encoder Folder

                try
                {
                    var encoderFolder = Path.GetDirectoryName(listFrames[0].ImageLocation);

                    if (!string.IsNullOrEmpty(encoderFolder))
                    {
                        if (Directory.Exists(encoderFolder))
                        {
                            Directory.Delete(encoderFolder, true);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogWriter.Log(ex, "Cleaning the Encode folder");
                }

                #endregion

                GC.Collect();
            }
        }
Esempio n. 3
0
        private void Encode(List <FrameInfo> listFrames, int id, string fileName, Export type, CancellationTokenSource tokenSource)
        {
            if (type == Export.Gif)
            {
                #region Gif

                if (Settings.Default.CustomEncoding)
                {
                    #region Custom Gif Encoding

                    using (var encoder = new AnimatedGifEncoder())
                    {
                        string cutFolder = null;

                        #region Cut/Paint Unchanged Pixels

                        if (Settings.Default.DetectUnchanged)
                        {
                            Update(id, 0, "Analizing Unchanged Pixels");

                            if (Settings.Default.PaintTransparent)
                            {
                                var color = Color.FromArgb(Settings.Default.TransparentColor.R,
                                                           Settings.Default.TransparentColor.G, Settings.Default.TransparentColor.B);

                                listFrames = ImageMethods.PaintTransparentAndCut(listFrames, color, id, tokenSource);

                                //TODO: Use System.Windows.Media.Color inside the AnimatedGifEncoder.
                                encoder.SetTransparent(color);
                                encoder.SetDispose(1); //Undraw Method, "Leave".
                            }
                            else
                            {
                                listFrames = ImageMethods.CutUnchanged(listFrames, id, tokenSource);
                            }
                        }

                        #endregion

                        encoder.Start(fileName);
                        encoder.SetQuality(Settings.Default.Quality);
                        encoder.SetRepeat(Settings.Default.Looped ? (Settings.Default.RepeatForever ? 0 : Settings.Default.RepeatCount) : -1); // 0 = Always, -1 once

                        int numImage = 0;
                        foreach (FrameInfo image in listFrames)
                        {
                            #region Cancellation

                            if (tokenSource.Token.IsCancellationRequested)
                            {
                                SetStatus(Status.Cancelled, id);

                                break;
                            }

                            #endregion

                            var bitmapAux = new Bitmap(image.ImageLocation);

                            encoder.SetDelay(image.Delay);
                            encoder.AddFrame(bitmapAux, image.PositionTopLeft.X, image.PositionTopLeft.Y);

                            bitmapAux.Dispose();

                            Update(id, numImage, "Processing " + numImage);
                            numImage++;
                        }

                        #region Specific Clear

                        try
                        {
                            if (!String.IsNullOrEmpty(cutFolder))
                            {
                                if (Directory.Exists(cutFolder))
                                {
                                    Directory.Delete(cutFolder, true);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            LogWriter.Log(ex, "Errow while Deleting and Cleaning Specific Variables");
                        }

                        #endregion
                    }

                    #endregion
                }
                else
                {
                    #region paint.NET encoding

                    //0 = Always, -1 = no repeat, n = repeat number (first shown + repeat number = total number of iterations)
                    var repeat = (Settings.Default.Looped ? (Settings.Default.RepeatForever ? 0 : Settings.Default.RepeatCount) : -1);

                    using (var stream = new MemoryStream())
                    {
                        using (var encoderNet = new GifEncoder(stream, null, null, repeat))
                        {
                            for (int i = 0; i < listFrames.Count; i++)
                            {
                                var bitmapAux = new Bitmap(listFrames[i].ImageLocation);
                                encoderNet.AddFrame(bitmapAux, 0, 0, TimeSpan.FromMilliseconds(listFrames[i].Delay));
                                bitmapAux.Dispose();

                                Update(id, i, "Processing " + i);

                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Cancelled, id);

                                    break;
                                }

                                #endregion
                            }
                        }

                        stream.Position = 0;

                        try
                        {
                            using (var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None,
                                                                   Constants.BufferSize, false))
                            {
                                stream.WriteTo(fileStream);
                            }
                        }
                        catch (Exception ex)
                        {
                            SetStatus(Status.Error, id);
                            LogWriter.Log(ex, "Error while writing to disk.");
                        }
                    }

                    #endregion
                }

                #endregion
            }
            else
            {
                #region Avi

                var image = listFrames[0].ImageLocation.SourceFrom();

                using (var aviWriter = new AviWriter(fileName, 1000 / listFrames[0].Delay,
                                                     (int)image.PixelWidth, (int)image.PixelHeight, 5000))
                {
                    int numImage = 0;
                    foreach (FrameInfo frame in listFrames)
                    {
                        using (MemoryStream outStream = new MemoryStream())
                        {
                            var bitImage = frame.ImageLocation.SourceFrom();

                            var enc = new BmpBitmapEncoder();
                            enc.Frames.Add(BitmapFrame.Create(bitImage));
                            enc.Save(outStream);

                            outStream.Flush();

                            using (var bitmap = new Bitmap(outStream))
                            {
                                aviWriter.AddFrame(bitmap);
                            }
                        }

                        //aviWriter.AddFrame(new BitmapImage(new Uri(frame.ImageLocation)));

                        Update(id, numImage, "Processing " + numImage);
                        numImage++;

                        #region Cancellation

                        if (tokenSource.Token.IsCancellationRequested)
                        {
                            SetStatus(Status.Cancelled, id);
                            break;
                        }

                        #endregion
                    }
                }

                #endregion
            }

            #region Delete Encoder Folder

            try
            {
                var encoderFolder = Path.GetDirectoryName(listFrames[0].ImageLocation);

                if (!String.IsNullOrEmpty(encoderFolder))
                {
                    if (Directory.Exists(encoderFolder))
                    {
                        Directory.Delete(encoderFolder, true);
                    }
                }
            }
            catch (Exception ex)
            {
                LogWriter.Log(ex, "Errow while deleting and cleaning the Encode folder");
            }

            #endregion

            GC.Collect();

            if (!tokenSource.Token.IsCancellationRequested)
            {
                SetStatus(Status.Completed, id, fileName);
            }
        }
Esempio n. 4
0
        private void Encode(List <FrameInfo> listFrames, int id, Parameters param, CancellationTokenSource tokenSource)
        {
            var processing = FindResource("Encoder.Processing").ToString();

            try
            {
                switch (param.Type)
                {
                case Export.Gif:

                    #region Gif

                    #region Cut/Paint Unchanged Pixels

                    if (param.EncoderType == GifEncoderType.Legacy || param.EncoderType == GifEncoderType.ScreenToGif)
                    {
                        if (param.DetectUnchangedPixels)
                        {
                            Update(id, 0, FindResource("Encoder.Analyzing").ToString());

                            if (param.DummyColor.HasValue)
                            {
                                var color = Color.FromArgb(param.DummyColor.Value.R, param.DummyColor.Value.G, param.DummyColor.Value.B);

                                listFrames = ImageMethods.PaintTransparentAndCut(listFrames, color, id, tokenSource);
                            }
                            else
                            {
                                listFrames = ImageMethods.CutUnchanged(listFrames, id, tokenSource);
                            }
                        }
                        else
                        {
                            var size = listFrames[0].Path.ScaledSize();
                            listFrames.ForEach(x => x.Rect = new Int32Rect(0, 0, (int)size.Width, (int)size.Height));
                        }
                    }

                    #endregion

                    switch (param.EncoderType)
                    {
                    case GifEncoderType.ScreenToGif:

                        #region Improved encoding

                        using (var stream = new MemoryStream())
                        {
                            using (var encoder = new GifFile(stream, param.RepeatCount))
                            {
                                encoder.UseGlobalColorTable = param.UseGlobalColorTable;
                                encoder.TransparentColor    = param.DummyColor;
                                encoder.MaximumNumberColor  = param.MaximumNumberColors;

                                for (var i = 0; i < listFrames.Count; i++)
                                {
                                    if (!listFrames[i].HasArea && param.DetectUnchangedPixels)
                                    {
                                        continue;
                                    }

                                    if (listFrames[i].Delay == 0)
                                    {
                                        listFrames[i].Delay = 10;
                                    }

                                    encoder.AddFrame(listFrames[i].Path, listFrames[i].Rect, listFrames[i].Delay);

                                    Update(id, i, string.Format(processing, i));

                                    #region Cancellation

                                    if (tokenSource.Token.IsCancellationRequested)
                                    {
                                        SetStatus(Status.Canceled, id);
                                        break;
                                    }

                                    #endregion
                                }
                            }

                            try
                            {
                                using (var fileStream = new FileStream(param.Filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096))
                                    stream.WriteTo(fileStream);
                            }
                            catch (Exception ex)
                            {
                                SetStatus(Status.Error, id);
                                LogWriter.Log(ex, "Improved Encoding");
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.Legacy:

                        #region Legacy Encoding

                        using (var encoder = new AnimatedGifEncoder())
                        {
                            if (param.DummyColor.HasValue)
                            {
                                var color = Color.FromArgb(param.DummyColor.Value.R,
                                                           param.DummyColor.Value.G, param.DummyColor.Value.B);

                                encoder.SetTransparent(color);
                                encoder.SetDispose(1);         //Undraw Method, "Leave".
                            }

                            encoder.Start(param.Filename);
                            encoder.SetQuality(param.Quality);
                            encoder.SetRepeat(param.RepeatCount);

                            var numImage = 0;
                            foreach (var frame in listFrames)
                            {
                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion

                                if (!frame.HasArea && param.DetectUnchangedPixels)
                                {
                                    continue;
                                }

                                var bitmapAux = new Bitmap(frame.Path);

                                encoder.SetDelay(frame.Delay);
                                encoder.AddFrame(bitmapAux, frame.Rect.X, frame.Rect.Y);

                                bitmapAux.Dispose();

                                Update(id, numImage, string.Format(processing, numImage));
                                numImage++;
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.PaintNet:

                        #region paint.NET encoding

                        using (var stream = new MemoryStream())
                        {
                            using (var encoder = new GifEncoder(stream, null, null, param.RepeatCount))
                            {
                                for (var i = 0; i < listFrames.Count; i++)
                                {
                                    var bitmapAux = new Bitmap(listFrames[i].Path);
                                    encoder.AddFrame(bitmapAux, 0, 0, TimeSpan.FromMilliseconds(listFrames[i].Delay));
                                    bitmapAux.Dispose();

                                    Update(id, i, string.Format(processing, i));

                                    #region Cancellation

                                    if (tokenSource.Token.IsCancellationRequested)
                                    {
                                        SetStatus(Status.Canceled, id);

                                        break;
                                    }

                                    #endregion
                                }
                            }

                            stream.Position = 0;

                            try
                            {
                                using (var fileStream = new FileStream(param.Filename, FileMode.Create, FileAccess.Write, FileShare.None, Constants.BufferSize, false))
                                    stream.WriteTo(fileStream);
                            }
                            catch (Exception ex)
                            {
                                SetStatus(Status.Error, id);
                                LogWriter.Log(ex, "Encoding with paint.Net.");
                            }
                        }

                        #endregion

                        break;

                    default:
                        throw new Exception("Undefined Gif encoder type");
                    }

                    #endregion

                    break;

                case Export.Apng:

                    #region Apng

                    #region Cut/Paint Unchanged Pixels

                    if (param.DetectUnchangedPixels)
                    {
                        Update(id, 0, FindResource("Encoder.Analyzing").ToString());

                        if (param.DummyColor.HasValue)
                        {
                            var color = Color.FromArgb(param.DummyColor.Value.A, param.DummyColor.Value.R, param.DummyColor.Value.G, param.DummyColor.Value.B);
                            listFrames = ImageMethods.PaintTransparentAndCut(listFrames, color, id, tokenSource);
                        }
                        else
                        {
                            listFrames = ImageMethods.CutUnchanged(listFrames, id, tokenSource);
                        }
                    }
                    else
                    {
                        var size = listFrames[0].Path.ScaledSize();
                        listFrames.ForEach(x => x.Rect = new Int32Rect(0, 0, (int)size.Width, (int)size.Height));
                    }

                    #endregion

                    #region Encoding

                    using (var stream = new MemoryStream())
                    {
                        var frameCount = listFrames.Count(x => x.HasArea);

                        using (var encoder = new Apng(stream, frameCount, param.RepeatCount))
                        {
                            for (var i = 0; i < listFrames.Count; i++)
                            {
                                if (!listFrames[i].HasArea && param.DetectUnchangedPixels)
                                {
                                    continue;
                                }

                                if (listFrames[i].Delay == 0)
                                {
                                    listFrames[i].Delay = 10;
                                }

                                encoder.AddFrame(listFrames[i].Path, listFrames[i].Rect, listFrames[i].Delay);

                                Update(id, i, string.Format(processing, i));

                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion
                            }
                        }

                        try
                        {
                            using (var fileStream = new FileStream(param.Filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096))
                                stream.WriteTo(fileStream);
                        }
                        catch (Exception ex)
                        {
                            SetStatus(Status.Error, id);
                            LogWriter.Log(ex, "Apng Encoding");
                        }
                    }

                    #endregion

                    #endregion

                    break;

                case Export.Video:

                    #region Video

                    switch (param.VideoEncoder)
                    {
                    case VideoEncoderType.AviStandalone:

                        #region Avi Standalone

                        var image = listFrames[0].Path.SourceFrom();

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        //1000 / listFrames[0].Delay
                        using (var aviWriter = new AviWriter(param.Filename, param.Framerate, image.PixelWidth, image.PixelHeight, param.VideoQuality))
                        {
                            var numImage = 0;
                            foreach (var frame in listFrames)
                            {
                                using (var outStream = new MemoryStream())
                                {
                                    var bitImage = frame.Path.SourceFrom();

                                    var enc = new BmpBitmapEncoder();
                                    enc.Frames.Add(BitmapFrame.Create(bitImage));
                                    enc.Save(outStream);

                                    outStream.Flush();

                                    using (var bitmap = new Bitmap(outStream))
                                        aviWriter.AddFrame(bitmap, param.FlipVideo);
                                }

                                Update(id, numImage, string.Format(processing, numImage));
                                numImage++;

                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion
                            }
                        }

                        #endregion

                        break;

                    case VideoEncoderType.Ffmpg:

                        #region Video using FFmpeg

                        SetStatus(Status.Encoding, id, null, true);

                        if (!Util.Other.IsFfmpegPresent())
                        {
                            throw new ApplicationException("FFmpeg not present.");
                        }

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        #region Generate concat

                        var concat = new StringBuilder();
                        foreach (var frame in listFrames)
                        {
                            concat.AppendLine("file '" + frame.Path + "'");
                            concat.AppendLine("duration " + (frame.Delay / 1000d).ToString(CultureInfo.InvariantCulture));
                        }

                        var concatPath = Path.GetDirectoryName(listFrames[0].Path) ?? Path.GetTempPath();
                        var concatFile = Path.Combine(concatPath, "concat.txt");

                        if (!Directory.Exists(concatPath))
                        {
                            Directory.CreateDirectory(concatPath);
                        }

                        if (File.Exists(concatFile))
                        {
                            File.Delete(concatFile);
                        }

                        File.WriteAllText(concatFile, concat.ToString());

                        #endregion

                        param.Command = string.Format(param.Command, concatFile, param.ExtraParameters.Replace("{H}", param.Height.ToString()).Replace("{W}", param.Width.ToString()), param.Filename);

                        var process = new ProcessStartInfo(UserSettings.All.FfmpegLocation)
                        {
                            Arguments             = param.Command,
                            CreateNoWindow        = true,
                            ErrorDialog           = false,
                            UseShellExecute       = false,
                            RedirectStandardError = true
                        };

                        var pro = Process.Start(process);

                        var str = pro.StandardError.ReadToEnd();

                        var fileInfo = new FileInfo(param.Filename);

                        if (!fileInfo.Exists || fileInfo.Length == 0)
                        {
                            throw new Exception("Error while encoding with FFmpeg.")
                                  {
                                      HelpLink = str
                                  }
                        }
                        ;

                        #endregion

                        break;

                    default:
                        throw new Exception("Undefined video encoder");
                    }

                    #endregion

                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(param));
                }

                if (!tokenSource.Token.IsCancellationRequested)
                {
                    SetStatus(Status.Completed, id, param.Filename);
                }

                #region Upload

                if (param.Upload && File.Exists(param.Filename))
                {
                    /*
                     * using (var w = new WebClient())
                     * {
                     *  var clientID = "15 digit key";
                     *  w.Headers.Add("Authorization", "Client-ID " + clientID);
                     *  var values = new NameValueCollection { { "image", Convert.ToBase64String(File.ReadAllBytes(@""+filename)) }};
                     *  var response = w.UploadValues("https://api.imgur.com/3/upload.xml", values);
                     *  var x = XDocument.Load(new MemoryStream(response));
                     *  var link = x.Descendants().Where(n => n.Name == "link").FirstOrDefault();
                     *  string href = link.Value;
                     * }
                     */
                }

                #endregion

                #region Copy to clipboard

                if (param.CopyToClipboard && File.Exists(param.Filename))
                {
                    Dispatcher.Invoke(() =>
                    {
                        try
                        {
                            var data = new DataObject();

                            switch (param.CopyType)
                            {
                            case CopyType.File:
                                if (param.Type != Export.Video)
                                {
                                    data.SetImage(param.Filename.SourceFrom());
                                }

                                data.SetText(param.Filename, TextDataFormat.Text);
                                data.SetFileDropList(new StringCollection {
                                    param.Filename
                                });
                                break;

                            case CopyType.FolderPath:
                                data.SetText(Path.GetDirectoryName(param.Filename) ?? param.Filename, TextDataFormat.Text);
                                break;

                            case CopyType.Link:
                                data.SetText(param.Filename, TextDataFormat.Text);     //TODO: Link.
                                break;

                            default:
                                data.SetText(param.Filename, TextDataFormat.Text);
                                break;
                            }

                            Clipboard.SetDataObject(data, true);
                            InternalSetCopy(id, true);
                        }
                        catch (Exception e)
                        {
                            LogWriter.Log(e, "It was not possible to copy the file.");
                            InternalSetCopy(id, false, e);
                        }
                    });
                }

                #endregion

                #region Execute commands

                if (param.ExecuteCommands && !string.IsNullOrWhiteSpace(param.PostCommands))
                {
                    var command = param.PostCommands.Replace("{p}", "\"" + param.Filename + "\"").Replace("{f}", "\"" + Path.GetDirectoryName(param.Filename) + "\"");
                    var output  = "";

                    try
                    {
                        foreach (var com in command.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            var procStartInfo = new ProcessStartInfo("cmd", "/c " + com)
                            {
                                RedirectStandardOutput = true,
                                RedirectStandardError  = true,
                                UseShellExecute        = false,
                                CreateNoWindow         = true
                            };

                            using (var process = new Process())
                            {
                                process.StartInfo = procStartInfo;
                                process.Start();

                                var message = process.StandardOutput.ReadToEnd();
                                var error   = process.StandardError.ReadToEnd();

                                if (!string.IsNullOrWhiteSpace(message))
                                {
                                    output += message + Environment.NewLine;
                                }

                                if (!string.IsNullOrWhiteSpace(message))
                                {
                                    output += message + Environment.NewLine;
                                }

                                if (!string.IsNullOrWhiteSpace(error))
                                {
                                    throw new Exception(error);
                                }

                                process.WaitForExit(1000);
                            }
                        }

                        InternalSetCommand(id, true, output);
                    }
                    catch (Exception e)
                    {
                        LogWriter.Log(e, "It was not possible to run the post encoding command.");
                        InternalSetCommand(id, false, output, e);
                    }
                }

                #endregion
            }
            catch (Exception ex)
            {
                LogWriter.Log(ex, "Encode");

                SetStatus(Status.Error, id, null, false, ex);
            }
            finally
            {
                #region Delete Encoder Folder

                try
                {
                    var encoderFolder = Path.GetDirectoryName(listFrames[0].Path);

                    if (!string.IsNullOrEmpty(encoderFolder))
                    {
                        if (Directory.Exists(encoderFolder))
                        {
                            Directory.Delete(encoderFolder, true);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogWriter.Log(ex, "Cleaning the Encode folder");
                }

                #endregion

                GC.Collect();
            }
        }
Esempio n. 5
0
        private void Encode(List <FrameInfo> listFrames, int id, Parameters param, CancellationTokenSource tokenSource)
        {
            var processing = this.DispatcherStringResource("Encoder.Processing");

            try
            {
                switch (param.Type)
                {
                case Export.Gif:

                    #region Gif

                    #region Cut/Paint Unchanged Pixels

                    if (param.EncoderType == GifEncoderType.Legacy || param.EncoderType == GifEncoderType.ScreenToGif)
                    {
                        if (param.DetectUnchangedPixels)
                        {
                            Update(id, 0, FindResource("Encoder.Analyzing").ToString());

                            if (param.DummyColor.HasValue)
                            {
                                var color = Color.FromArgb(param.DummyColor.Value.R, param.DummyColor.Value.G, param.DummyColor.Value.B);

                                listFrames = ImageMethods.PaintTransparentAndCut(listFrames, color, id, tokenSource);
                            }
                            else
                            {
                                listFrames = ImageMethods.CutUnchanged(listFrames, id, tokenSource);
                            }
                        }
                        else
                        {
                            var size = listFrames[0].Path.ScaledSize();
                            listFrames.ForEach(x => x.Rect = new Int32Rect(0, 0, (int)size.Width, (int)size.Height));
                        }
                    }

                    #endregion

                    switch (param.EncoderType)
                    {
                    case GifEncoderType.ScreenToGif:

                        #region Improved encoding

                        using (var stream = new MemoryStream())
                        {
                            using (var encoder = new GifFile(stream, param.RepeatCount))
                            {
                                encoder.UseGlobalColorTable = param.UseGlobalColorTable;
                                encoder.TransparentColor    = param.DummyColor;
                                encoder.MaximumNumberColor  = param.MaximumNumberColors;

                                for (var i = 0; i < listFrames.Count; i++)
                                {
                                    if (!listFrames[i].HasArea && param.DetectUnchangedPixels)
                                    {
                                        continue;
                                    }

                                    if (listFrames[i].Delay == 0)
                                    {
                                        listFrames[i].Delay = 10;
                                    }

                                    encoder.AddFrame(listFrames[i].Path, listFrames[i].Rect, listFrames[i].Delay);

                                    Update(id, i, string.Format(processing, i));

                                    #region Cancellation

                                    if (tokenSource.Token.IsCancellationRequested)
                                    {
                                        SetStatus(Status.Canceled, id);
                                        break;
                                    }

                                    #endregion
                                }
                            }

                            try
                            {
                                using (var fileStream = new FileStream(param.Filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096))
                                    stream.WriteTo(fileStream);
                            }
                            catch (Exception ex)
                            {
                                SetStatus(Status.Error, id);
                                LogWriter.Log(ex, "Improved Encoding");
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.Legacy:

                        #region Legacy Encoding

                        using (var encoder = new AnimatedGifEncoder())
                        {
                            if (param.DummyColor.HasValue)
                            {
                                var color = Color.FromArgb(param.DummyColor.Value.R,
                                                           param.DummyColor.Value.G, param.DummyColor.Value.B);

                                encoder.SetTransparent(color);
                                encoder.SetDispose(1);         //Undraw Method, "Leave".
                            }

                            encoder.Start(param.Filename);
                            encoder.SetQuality(param.Quality);
                            encoder.SetRepeat(param.RepeatCount);

                            var numImage = 0;
                            foreach (var frame in listFrames)
                            {
                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion

                                if (!frame.HasArea && param.DetectUnchangedPixels)
                                {
                                    continue;
                                }

                                var bitmapAux = new Bitmap(frame.Path);

                                encoder.SetDelay(frame.Delay);
                                encoder.AddFrame(bitmapAux, frame.Rect.X, frame.Rect.Y);

                                bitmapAux.Dispose();

                                Update(id, numImage, string.Format(processing, numImage));
                                numImage++;
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.PaintNet:

                        #region paint.NET encoding

                        using (var stream = new MemoryStream())
                        {
                            using (var encoder = new GifEncoder(stream, null, null, param.RepeatCount))
                            {
                                for (var i = 0; i < listFrames.Count; i++)
                                {
                                    var bitmapAux = new Bitmap(listFrames[i].Path);
                                    encoder.AddFrame(bitmapAux, 0, 0, TimeSpan.FromMilliseconds(listFrames[i].Delay));
                                    bitmapAux.Dispose();

                                    Update(id, i, string.Format(processing, i));

                                    #region Cancellation

                                    if (tokenSource.Token.IsCancellationRequested)
                                    {
                                        SetStatus(Status.Canceled, id);

                                        break;
                                    }

                                    #endregion
                                }
                            }

                            stream.Position = 0;

                            try
                            {
                                using (var fileStream = new FileStream(param.Filename, FileMode.Create, FileAccess.Write, FileShare.None, Constants.BufferSize, false))
                                    stream.WriteTo(fileStream);
                            }
                            catch (Exception ex)
                            {
                                SetStatus(Status.Error, id);
                                LogWriter.Log(ex, "Encoding with paint.Net.");
                            }
                        }

                        #endregion

                        break;

                    case GifEncoderType.FFmpeg:

                        #region FFmpeg encoding

                        SetStatus(Status.Processing, id, null, true);

                        if (!Util.Other.IsFfmpegPresent())
                        {
                            throw new ApplicationException("FFmpeg not present.");
                        }

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        #region Generate concat

                        var concat = new StringBuilder();
                        foreach (var frame in listFrames)
                        {
                            concat.AppendLine("file '" + frame.Path + "'");
                            concat.AppendLine("duration " + (frame.Delay / 1000d).ToString(CultureInfo.InvariantCulture));
                        }

                        var concatPath = Path.GetDirectoryName(listFrames[0].Path) ?? Path.GetTempPath();
                        var concatFile = Path.Combine(concatPath, "concat.txt");

                        if (!Directory.Exists(concatPath))
                        {
                            Directory.CreateDirectory(concatPath);
                        }

                        if (File.Exists(concatFile))
                        {
                            File.Delete(concatFile);
                        }

                        File.WriteAllText(concatFile, concat.ToString());

                        #endregion

                        param.Command = string.Format(param.Command, concatFile, param.ExtraParameters.Replace("{H}", param.Height.ToString()).Replace("{W}", param.Width.ToString()), param.Filename);

                        var process = new ProcessStartInfo(UserSettings.All.FfmpegLocation)
                        {
                            Arguments             = param.Command,
                            CreateNoWindow        = true,
                            ErrorDialog           = false,
                            UseShellExecute       = false,
                            RedirectStandardError = true
                        };

                        var pro = Process.Start(process);

                        var str = pro.StandardError.ReadToEnd();

                        var fileInfo = new FileInfo(param.Filename);

                        if (!fileInfo.Exists || fileInfo.Length == 0)
                        {
                            throw new Exception("Error while encoding the gif with FFmpeg.")
                                  {
                                      HelpLink = str
                                  }
                        }
                        ;

                        #endregion

                        break;

                    case GifEncoderType.Gifski:

                        #region Gifski encoding

                        SetStatus(Status.Processing, id, null, true);

                        if (!Util.Other.IsGifskiPresent())
                        {
                            throw new ApplicationException("Gifski not present.");
                        }

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        var outputPath = Path.GetDirectoryName(listFrames[0].Path);
                        var fps        = !param.ExtraParameters.Contains("--fps") ? "--fps " + (int)(1000d / listFrames.Average(x => x.Delay)) : "";

                        param.Command = $"{param.ExtraParameters} {fps} -o \"{param.Filename}\" \"{Path.Combine(outputPath, "*.png")}\"";

                        var process2 = new ProcessStartInfo(UserSettings.All.GifskiLocation)
                        {
                            Arguments             = param.Command,
                            CreateNoWindow        = true,
                            ErrorDialog           = false,
                            UseShellExecute       = false,
                            RedirectStandardError = true
                        };

                        var pro2 = Process.Start(process2);

                        var str2 = pro2.StandardError.ReadToEnd();

                        var fileInfo2 = new FileInfo(param.Filename);

                        if (!fileInfo2.Exists || fileInfo2.Length == 0)
                        {
                            throw new Exception("Error while encoding the gif with Gifski.")
                                  {
                                      HelpLink = str2
                                  }
                        }
                        ;

                        #endregion

                        break;

                    default:
                        throw new Exception("Undefined Gif encoder type");
                    }

                    #endregion

                    break;

                case Export.Apng:

                    #region Apng

                    #region Cut/Paint Unchanged Pixels

                    if (param.DetectUnchangedPixels)
                    {
                        Update(id, 0, FindResource("Encoder.Analyzing").ToString());

                        if (param.DummyColor.HasValue)
                        {
                            var color = Color.FromArgb(param.DummyColor.Value.A, param.DummyColor.Value.R, param.DummyColor.Value.G, param.DummyColor.Value.B);
                            listFrames = ImageMethods.PaintTransparentAndCut(listFrames, color, id, tokenSource);
                        }
                        else
                        {
                            listFrames = ImageMethods.CutUnchanged(listFrames, id, tokenSource);
                        }
                    }
                    else
                    {
                        var size = listFrames[0].Path.ScaledSize();
                        listFrames.ForEach(x => x.Rect = new Int32Rect(0, 0, (int)size.Width, (int)size.Height));
                    }

                    #endregion

                    #region Encoding

                    using (var stream = new MemoryStream())
                    {
                        var frameCount = listFrames.Count(x => x.HasArea);

                        using (var encoder = new Apng(stream, frameCount, param.RepeatCount))
                        {
                            for (var i = 0; i < listFrames.Count; i++)
                            {
                                if (!listFrames[i].HasArea && param.DetectUnchangedPixels)
                                {
                                    continue;
                                }

                                if (listFrames[i].Delay == 0)
                                {
                                    listFrames[i].Delay = 10;
                                }

                                encoder.AddFrame(listFrames[i].Path, listFrames[i].Rect, listFrames[i].Delay);

                                Update(id, i, string.Format(processing, i));

                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion
                            }
                        }

                        try
                        {
                            using (var fileStream = new FileStream(param.Filename, FileMode.Create, FileAccess.Write, FileShare.None, 4096))
                                stream.WriteTo(fileStream);
                        }
                        catch (Exception ex)
                        {
                            SetStatus(Status.Error, id);
                            LogWriter.Log(ex, "Apng Encoding");
                        }
                    }

                    #endregion

                    #endregion

                    break;

                case Export.Video:

                    #region Video

                    switch (param.VideoEncoder)
                    {
                    case VideoEncoderType.AviStandalone:

                        #region Avi Standalone

                        var image = listFrames[0].Path.SourceFrom();

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        //1000 / listFrames[0].Delay
                        using (var aviWriter = new AviWriter(param.Filename, param.Framerate, image.PixelWidth, image.PixelHeight, param.VideoQuality))
                        {
                            var numImage = 0;
                            foreach (var frame in listFrames)
                            {
                                using (var outStream = new MemoryStream())
                                {
                                    var bitImage = frame.Path.SourceFrom();

                                    var enc = new BmpBitmapEncoder();
                                    enc.Frames.Add(BitmapFrame.Create(bitImage));
                                    enc.Save(outStream);

                                    outStream.Flush();

                                    using (var bitmap = new Bitmap(outStream))
                                        aviWriter.AddFrame(bitmap, param.FlipVideo);
                                }

                                Update(id, numImage, string.Format(processing, numImage));
                                numImage++;

                                #region Cancellation

                                if (tokenSource.Token.IsCancellationRequested)
                                {
                                    SetStatus(Status.Canceled, id);
                                    break;
                                }

                                #endregion
                            }
                        }

                        #endregion

                        break;

                    case VideoEncoderType.Ffmpg:

                        #region Video using FFmpeg

                        SetStatus(Status.Processing, id, null, true);

                        if (!Util.Other.IsFfmpegPresent())
                        {
                            throw new ApplicationException("FFmpeg not present.");
                        }

                        if (File.Exists(param.Filename))
                        {
                            File.Delete(param.Filename);
                        }

                        #region Generate concat

                        var concat = new StringBuilder();
                        foreach (var frame in listFrames)
                        {
                            concat.AppendLine("file '" + frame.Path + "'");
                            concat.AppendLine("duration " + (frame.Delay / 1000d).ToString(CultureInfo.InvariantCulture));
                        }

                        var concatPath = Path.GetDirectoryName(listFrames[0].Path) ?? Path.GetTempPath();
                        var concatFile = Path.Combine(concatPath, "concat.txt");

                        if (!Directory.Exists(concatPath))
                        {
                            Directory.CreateDirectory(concatPath);
                        }

                        if (File.Exists(concatFile))
                        {
                            File.Delete(concatFile);
                        }

                        File.WriteAllText(concatFile, concat.ToString());

                        #endregion

                        param.Command = string.Format(param.Command, concatFile, param.ExtraParameters.Replace("{H}", param.Height.ToString()).Replace("{W}", param.Width.ToString()), param.Filename);

                        var process = new ProcessStartInfo(UserSettings.All.FfmpegLocation)
                        {
                            Arguments             = param.Command,
                            CreateNoWindow        = true,
                            ErrorDialog           = false,
                            UseShellExecute       = false,
                            RedirectStandardError = true
                        };

                        var pro = Process.Start(process);

                        var str = pro.StandardError.ReadToEnd();

                        var fileInfo = new FileInfo(param.Filename);

                        if (!fileInfo.Exists || fileInfo.Length == 0)
                        {
                            throw new Exception("Error while encoding with FFmpeg.")
                                  {
                                      HelpLink = str
                                  }
                        }
                        ;

                        #endregion

                        break;

                    default:
                        throw new Exception("Undefined video encoder");
                    }

                    #endregion

                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(param));
                }

                //If it was canceled, try deleting the file.
                if (tokenSource.Token.IsCancellationRequested)
                {
                    if (File.Exists(param.Filename))
                    {
                        File.Delete(param.Filename);
                    }

                    SetStatus(Status.Canceled, id);
                    return;
                }

                #region Upload

                if (param.Upload && File.Exists(param.Filename))
                {
                    InternalUpdate(id, "Encoder.Uploading", true, true);

                    try
                    {
                        //TODO: Make it less hardcoded.
                        switch (param.UploadDestinationIndex)
                        {
                        case 0:     //Imgur.
                            using (var w = new WebClient())
                            {
                                w.Headers.Add("Authorization", "Client-ID " + Secret.ImgurId);
                                var values = new NameValueCollection {
                                    { "image", Convert.ToBase64String(File.ReadAllBytes(param.Filename)) }
                                };
                                var response = w.UploadValues("https://api.imgur.com/3/upload.xml", values);
                                var x        = XDocument.Load(new MemoryStream(response));

                                var node     = x.Descendants().FirstOrDefault(n => n.Name == "link");
                                var nodeHash = x.Descendants().FirstOrDefault(n => n.Name == "deletehash");

                                if (node == null)
                                {
                                    throw new Exception("No link was provided by Imgur", new Exception(x.Document?.ToString() ?? "The document was null. :/"));
                                }

                                InternalSetUpload(id, true, node.Value, "https://imgur.com/delete/" + nodeHash?.Value);
                            }
                            break;

                        case 1:     //Gfycat.
                            using (var client = new HttpClient())
                            {
                                using (var res = client.PostAsync(@"https://api.gfycat.com/v1/gfycats", null).Result)
                                {
                                    var result = res.Content.ReadAsStringAsync().Result;
                                    //{"isOk":true,"gfyname":"ThreeWordCode","secret":"15alphanumerics","uploadType":"filedrop.gfycat.com"}

                                    var ser = new JavaScriptSerializer();

                                    if (!(ser.DeserializeObject(result) is Dictionary <string, object> thing))
                                    {
                                        throw new Exception("It was not possible to get the gfycat name: " + res);
                                    }

                                    var name = thing["gfyname"] as string;

                                    using (var content = new MultipartFormDataContent())
                                    {
                                        content.Add(new StringContent(name), "key");
                                        content.Add(new ByteArrayContent(File.ReadAllBytes(param.Filename)), "file", name);

                                        using (var res2 = client.PostAsync("https://filedrop.gfycat.com", content).Result)
                                        {
                                            if (!res2.IsSuccessStatusCode)
                                            {
                                                throw new Exception("It was not possible to get the gfycat upload result: " + res2);
                                            }

                                            //{"task": "complete", "gfyname": "ThreeWordCode"}
                                            //{"progress": "0.03", "task": "encoding", "time": 10}

                                            //If the task is not yet completed, try waiting.

                                            var input2 = "";

                                            while (!input2.Contains("complete"))
                                            {
                                                using (var res3 = client.GetAsync("https://api.gfycat.com/v1/gfycats/fetch/status/" + name).Result)
                                                {
                                                    input2 = res3.Content.ReadAsStringAsync().Result;

                                                    if (!res3.IsSuccessStatusCode)
                                                    {
                                                        throw new Exception("It was not possible to get the gfycat upload status: " + res3);
                                                    }
                                                }

                                                if (!input2.Contains("complete"))
                                                {
                                                    Thread.Sleep(1000);
                                                }
                                            }

                                            if (res2.IsSuccessStatusCode)
                                            {
                                                InternalSetUpload(id, true, "https://gfycat.com/" + name);
                                            }
                                        }
                                    }
                                }
                            }
                            break;
                        }
                    }
                    catch (Exception e)
                    {
                        LogWriter.Log(e, "It was not possible to run the post encoding command.");
                        InternalSetUpload(id, false, null, null, e);
                    }
                }

                #endregion

                #region Copy to clipboard

                if (param.CopyToClipboard && File.Exists(param.Filename))
                {
                    Dispatcher.Invoke(() =>
                    {
                        try
                        {
                            var data = new DataObject();

                            switch (param.CopyType)
                            {
                            case CopyType.File:
                                if (param.Type != Export.Video)
                                {
                                    data.SetImage(param.Filename.SourceFrom());
                                }

                                data.SetText(param.Filename, TextDataFormat.Text);
                                data.SetFileDropList(new StringCollection {
                                    param.Filename
                                });
                                break;

                            case CopyType.FolderPath:
                                data.SetText(Path.GetDirectoryName(param.Filename) ?? param.Filename, TextDataFormat.Text);
                                break;

                            case CopyType.Link:
                                data.SetText(param.Filename, TextDataFormat.Text);     //TODO: Link.
                                break;

                            default:
                                data.SetText(param.Filename, TextDataFormat.Text);
                                break;
                            }

                            Clipboard.SetDataObject(data, true);
                            InternalSetCopy(id, true);
                        }
                        catch (Exception e)
                        {
                            LogWriter.Log(e, "It was not possible to copy the file.");
                            InternalSetCopy(id, false, e);
                        }
                    });
                }

                #endregion

                #region Execute commands

                if (param.ExecuteCommands && !string.IsNullOrWhiteSpace(param.PostCommands))
                {
                    InternalUpdate(id, "Encoder.Executing", true, true);

                    var command = param.PostCommands.Replace("{p}", "\"" + param.Filename + "\"").Replace("{f}", "\"" + Path.GetDirectoryName(param.Filename) + "\"");
                    var output  = "";

                    try
                    {
                        foreach (var com in command.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries))
                        {
                            var procStartInfo = new ProcessStartInfo("cmd", "/c " + com)
                            {
                                RedirectStandardOutput = true,
                                RedirectStandardError  = true,
                                UseShellExecute        = false,
                                CreateNoWindow         = true
                            };

                            using (var process = new Process())
                            {
                                process.StartInfo = procStartInfo;
                                process.Start();

                                var message = process.StandardOutput.ReadToEnd();
                                var error   = process.StandardError.ReadToEnd();

                                if (!string.IsNullOrWhiteSpace(message))
                                {
                                    output += message + Environment.NewLine;
                                }

                                if (!string.IsNullOrWhiteSpace(message))
                                {
                                    output += message + Environment.NewLine;
                                }

                                if (!string.IsNullOrWhiteSpace(error))
                                {
                                    throw new Exception(error);
                                }

                                process.WaitForExit(1000);
                            }
                        }

                        InternalSetCommand(id, true, command, output);
                    }
                    catch (Exception e)
                    {
                        LogWriter.Log(e, "It was not possible to run the post encoding command.");
                        InternalSetCommand(id, false, command, output, e);
                    }
                }

                #endregion

                if (!tokenSource.Token.IsCancellationRequested)
                {
                    SetStatus(Status.Completed, id, param.Filename);
                }
            }
            catch (Exception ex)
            {
                LogWriter.Log(ex, "Encode");

                SetStatus(Status.Error, id, null, false, ex);
            }
            finally
            {
                #region Delete Encoder Folder

                try
                {
                    var encoderFolder = Path.GetDirectoryName(listFrames[0].Path);

                    if (!string.IsNullOrEmpty(encoderFolder))
                    {
                        if (Directory.Exists(encoderFolder))
                        {
                            Directory.Delete(encoderFolder, true);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogWriter.Log(ex, "Cleaning the Encode folder");
                }

                #endregion

                GC.Collect();
            }
        }