// TODO organise /// <summary> /// Encodes a compressed byte[] list containing image data as a gif to the desired location /// </summary> /// <param name="frames">Compressed byte array defining an image</param> /// <param name="delay">The delay between frames</param> /// <param name="quality">The quality of the gif</param> /// <param name="repeat">Repeat mode</param> /// <param name="location">Where the gif will be saved</param> /// <param name="percentageProgress">Interface used to determine the current task progress</param> /// <param name="fromIndex">From which index will the list of frames start to be encoded</param> /// <param name="toIndex">Until which index will the list of frames be encoded</param> /// <param name="frameIndexIncremet">Used to skip frames if <see cref="frameIndexIncremet"/> > 1</param> public static async Task EncodeGifBytes( List <byte[]> frames, int delay, int quality, int repeat, string location, IProgress <float> percentageProgress, int fromIndex = 0, int toIndex = -1, int frameIndexIncremet = 1) { if (toIndex < 0) { toIndex = frames.Count; } await Task.Run(() => { var age = new AnimatedGifEncoder(); age.Start(location); age.SetDelay(delay); age.SetQuality(quality); age.SetRepeat(repeat); for (int i = fromIndex; i < toIndex; i += frameIndexIncremet) { if (percentageProgress != null) { percentageProgress.Report((float)(i - fromIndex) / (float)(toIndex - fromIndex)); } age.AddFrame(BytesToImage(frames[i])); } age.Finish(); }); }
private void GenerateGif(string tempFolder, string gifPath) { successful = false; if (!Directory.Exists(gifPath)) { Directory.CreateDirectory(gifPath); } string _GifFileName = "gf_" + DateTime.Now.Ticks.ToString() + ".gif"; gifPath = Path.Combine(gifPath, _GifFileName); gPath = gifPath; try { var _fileExtension = System.IO.Path.GetExtension(ShortPathGIF); var files = Directory.GetFiles(tempFolder, "*" + _fileExtension); AnimatedGifEncoder e = new AnimatedGifEncoder(); e.Start(gifPath); e.SetQuality(100); e.SetDelay(framedelaytimer); e.SetSize((int)ExportWidth, (int)ExportHeight); //e.SetFrameRate(15); //-1:no repeat,0:always repeat e.SetRepeat(0); if (RotationCheck) { e.AddFrame(Image.FromFile(files[0])); for (int i = files.Length - 1, count = -1; i > count; i--) { e.AddFrame(Image.FromFile(files[i])); } } else { for (int i = 0, count = files.Length; i < count; i++) { e.AddFrame(Image.FromFile(files[i])); } e.AddFrame(Image.FromFile(files[0])); } e.Finish(); GC.Collect(); successful = true; } catch (Exception ex) { Log.Debug("", ex); } //if (successful == true) //{ // MessageBox.Show("Saved Successfully at location.." + Environment.NewLine + gifPath, "ExportGIF", MessageBoxButton.OK, MessageBoxImage.Information); //} }
private void SaveImg(Processor prcsr, Saver sr, bool colored) { if (prcsr.res != null) { if (gif) { //Console.WriteLine("Animating..."); AnimatedGifEncoder e = new AnimatedGifEncoder(); e.SetQuality(20); string fname = "out_anim" + (colored ? "_colored" : "_bw") + ".gif"; if (File.Exists(fname)) { File.Delete(fname); } e.Start(fname); e.SetDelay(gif_speed); e.SetRepeat(0); int s = GIF_Frames.GetLength(0); ProgressBar pb = new ProgressBar(s, 20); pb.start(); DateTime dt = new DateTime(); dt = DateTime.Now; for (int i = 0; i < s; i++) { pb.Progress(i); Console.SetCursorPosition(pb.size + 2, pb.y); Bitmap b = new Bitmap(sr.Save(GIF_Frames[i], colored)); b = new Bitmap(b, b.Width / 2, b.Height / 2); e.AddFrame(b); b.Dispose(); } pb.End(); Console.WriteLine("Total time taken: " + (DateTime.Now - dt)); e.Finish(); e.SetDispose(-1); } else { sr.Save(prcsr.res, colored).Save("out_ASCII" + (colored?"_colored":"_bw") + ".png"); } } }
public unsafe void ToStream(Stream output, string format) { format = format.ToLower().Replace(".", ""); if (format != "gif") // TODO: Can't set delay to BitmapEncoder { BitmapEncoder encoder = EncoderSelector.GetEncoder(format); foreach (IImage image in this) { BitmapSource bitmapSource = image.ToBitmapSource(); encoder.Frames.Add(BitmapFrame.Create(bitmapSource)); } encoder.Save(output); } else { AnimatedGifEncoder encoder = new AnimatedGifEncoder(); encoder.SetQuality(100); encoder.SetRepeat(0); encoder.Start(output); foreach (IImage image in this) { IntPtr ptr = (IntPtr)image.BeginPixelWorking(false); Bitmap frame = new Bitmap(image.Width, image.Height, image.Width * 4, System.Drawing.Imaging.PixelFormat.Format32bppPArgb, ptr); image.EndPixelWorking(); encoder.SetDelay(image.AnimationDelay); encoder.AddFrame(frame); frame.Dispose(); } encoder.Finish(); } }
/// <summary> /// 创建Gif /// </summary> /// <param name="lsFrame">一组按照顺序排列好的帧</param> /// <param name="saveGifPath">GIF保存的路径</param> /// <param name="delay">切换帧的时间间隔</param> public void CreateGif(List <string> lsFrame, string saveGifPath, int delay) { #region 使用 Gif.Components 创建 AnimatedGifEncoder eG = new AnimatedGifEncoder(); String[] imageFilePaths = lsFrame.ToArray(); String outputFilePath = saveGifPath; eG.Start(outputFilePath); eG.SetDelay(delay); // 延迟间隔 eG.SetRepeat(0); //-1:不循环,0:总是循环 播放 eG.SetQuality(100); for (int i = 0, count = imageFilePaths.Length; i < count; i++) { eG.AddFrame(Image.FromFile(imageFilePaths[i])); } eG.Finish(); #endregion }
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(); } }
private void RenderToGIF(Image[] images) { string outPath = ""; Start: if (!String.IsNullOrEmpty(ScreenCapBgLocText.Text)) { try { outPath = ScreenCapBgLocText.Text; if (!Directory.Exists(outPath)) { Directory.CreateDirectory(outPath); } DirectoryInfo dir = new DirectoryInfo(outPath); FileInfo[] files = dir.GetFiles(); int i = 0; string name = "BrawlboxAnimation"; Top: foreach (FileInfo f in files) { if (f.Name == name + i + ".gif") { i++; goto Top; } } outPath += "\\" + name + i + ".gif"; } catch { } } else { ScreenCapBgLocText.Text = Application.StartupPath + "\\ScreenCaptures"; goto Start; } AnimatedGifEncoder e = new AnimatedGifEncoder(); e.Start(outPath); e.SetDelay(1000 / (int)pnlPlayback.numFPS.Value); e.SetRepeat(0); e.SetQuality(1); using (ProgressWindow progress = new ProgressWindow(this, "GIF Encoder", "Encoding, please wait...", true)) { progress.TopMost = true; progress.Begin(0, images.Length, 0); for (int i = 0, count = images.Length; i < count; i++) { if (progress.Cancelled) { break; } e.AddFrame(images[i]); progress.Update(progress.CurrentValue + 1); } progress.Finish(); e.Finish(); } if (InterpolationEditor != null) { InterpolationEditor.Enabled = true; } ModelPanel.Enabled = true; Enabled = true; MessageBox.Show("GIF successfully saved to " + outPath.Replace("\\", "/")); }
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(); } }
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); } }
private void RenderToGIF(List <Image> images, string path) { if (string.IsNullOrEmpty(path)) { return; } string outPath = ""; try { outPath = path; if (!Directory.Exists(outPath)) { Directory.CreateDirectory(outPath); } DirectoryInfo dir = new DirectoryInfo(outPath); FileInfo[] files = dir.GetFiles(); int i = 0; string name = "Animation"; Top: foreach (FileInfo f in files) { if (f.Name == name + i + ".gif") { i++; goto Top; } } outPath += "\\" + name + i + ".gif"; } catch { // ignored } AnimatedGifEncoder e = new AnimatedGifEncoder(); e.Start(outPath); e.SetDelay(1000 / (int)PlaybackPanel.numFPS.Value); e.SetRepeat(0); e.SetQuality(10); using (ProgressWindow progress = new ProgressWindow(this, "GIF Encoder", "Encoding, please wait...", true)) { progress.TopMost = true; progress.Begin(0, images.Count, 0); for (int i = 0, count = images.Count; i < count; i++) { if (progress.Cancelled) { break; } //GIF transparency support is pretty poor, flickers a lot //e.SetTransparent(ModelPanel.CurrentViewport.BackgroundColor); e.AddFrame(images[i]); progress.Update(progress.CurrentValue + 1); } progress.Finish(); e.Finish(); } _loop = PlaybackPanel.chkLoop.Checked; if (MessageBox.Show(this, "Animated GIF successfully saved to \"" + outPath.Replace("\\", "/") + "\".\nOpen the folder now?", "GIF saved", MessageBoxButtons.YesNo) == DialogResult.Yes) { Process.Start("explorer.exe", path); } }
/// <summary> /// Thread method that encodes the list of frames. /// </summary> private void DoWork() { int countList = _listBitmap.Count; var processing = new Processing(); this.Invoke((Action) delegate //Needed because it's a cross thread call. { //Control ctrlParent = panelTransparent; //Processing processing = new Processing(); panelTransparent.Controls.Add(processing); processing.Dock = DockStyle.Fill; processing.SetMaximumValue(countList); processing.SetStatus(1); }); if (Settings.Default.STencodingCustom) // if NGif encoding { #region Ngif encoding int numImage = 0; using (_encoder = new AnimatedGifEncoder()) { _encoder.Start(_outputpath); _encoder.SetQuality(Settings.Default.STquality); _encoder.SetRepeat(Settings.Default.STloop ? (Settings.Default.STrepeatForever ? 0 : Settings.Default.STrepeatCount) : -1); // 0 = Always, -1 once try { foreach (var image in _listBitmap) { numImage++; this.BeginInvoke((Action)(() => processing.SetStatus(numImage))); _encoder.SetFrameRate(Convert.ToInt32(numMaxFps.Value)); _encoder.AddFrame(image); } } catch (Exception ex) { LogWriter.Log(ex, "Ngif encoding."); } } #endregion } else //if paint.NET encoding { #region paint.NET encoding //var imageArray = _listBitmap.ToArray(); var delay = 1000 / Convert.ToInt32(numMaxFps.Value); var repeat = (Settings.Default.STloop ? (Settings.Default.STrepeatForever ? 0 : Settings.Default.STrepeatCount) : -1); // 0 = Always, -1 once using (var stream = new MemoryStream()) { using (var encoderNet = new GifEncoder(stream, null, null, repeat)) { for (int i = 0; i < _listBitmap.Count; i++) { encoderNet.AddFrame((_listBitmap[i]).CopyImage(), 0, 0, TimeSpan.FromMilliseconds(delay)); this.Invoke((Action)(() => processing.SetStatus(i))); } } stream.Position = 0; using ( var fileStream = new FileStream(_outputpath, FileMode.Create, FileAccess.Write, FileShare.None, Constants.BufferSize, false)) { stream.WriteTo(fileStream); } } #endregion } #region Memory Clearing //TODO: Clean the list of delay. listFramesPrivate.Clear(); listFramesUndo.Clear(); listFramesUndoAll.Clear(); listFramesPrivate = null; listFramesUndo = null; listFramesUndoAll = null; _encoder = null; GC.Collect(); //call the garbage colector to empty the memory #endregion #region Finish try { this.Invoke((Action) delegate //must use invoke because it's a cross thread call { _caller.Text = Resources.Title_EncodingDone; _stage = (int)Stage.Stoped; panelTransparent.Controls.Clear(); //Clears the processing page. processing.Dispose(); _caller.Invalidate(); btnRecordPause.Text = Resources.btnRecordPause_Record; btnRecordPause.Image = Properties.Resources.Record; flowPanel.Enabled = true; //_caller.TopMost = false; _caller.TopMost = false; numMaxFps.Enabled = true; tbHeight.Enabled = true; tbWidth.Enabled = true; _caller.MaximizeBox = true; _caller.MinimizeBox = true; _actHook.KeyDown += KeyHookTarget; //Set again the keyboard hook method _actHook.Start(false, true); //start again the keyboard hook watcher }); } catch (Exception ex) { LogWriter.Log(ex, "Invoke error."); } #endregion }
private void Form1_DragDrop(object sender, DragEventArgs e) { Thread workThread = new Thread(delegate() { string path = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString(); string dir = System.IO.Path.GetDirectoryName(path);//目錄名稱 string ext = System.IO.Path.GetExtension(path); string nam = System.IO.Path.GetFileNameWithoutExtension(path); if (ext != ".zip") { MessageBox.Show("請拖入zip格式檔案"); } else { this.label1.Text = "正在解壓"; System.Threading.Thread.Sleep(500); ZIP.UnpackFiles(path, dir + "/" + nam); this.label1.Text = "解壓完畢"; System.Threading.Thread.Sleep(500); this.label1.Text = "正在生成GIF"; System.Threading.Thread.Sleep(500); try { string[] jpgImgNames = Directory.GetFiles(dir + "/" + nam); // 获取各帧图片的文件名 string dtStr = DateTime.Now.ToString("yyyyMMddhhmmss"); string outPutPath = string.Format(dir + "/" + nam + ".gif", dtStr); // 生成要保存成的gif图片的文件名 // 创建动画(gif) AnimatedGifEncoder animate = new AnimatedGifEncoder(); animate.Start(outPutPath); animate.SetDelay(delay); animate.SetRepeat(repeat); // -1:不重复,0:无限循环 animate.SetQuality(qua); int filecount = 0; foreach (var item in jpgImgNames) { filecount++; Image imgFrame = Image.FromFile(item); this.label1.Text = "正在添加幀:\r\n" + System.IO.Path.GetFileNameWithoutExtension(item) + "\r\n" + filecount.ToString() + "/" + jpgImgNames.Length.ToString(); animate.AddFrame(imgFrame); // 添加帧 imgFrame.Dispose(); } animate.Finish(); this.label1.Text = "生成成功"; } catch (Exception ex) { this.label1.Text = "出錯啦:" + ex.Message; } try { DirectoryInfo di = new DirectoryInfo(dir + "/" + nam); di.Delete(true); } catch (Exception ex) { this.label1.Text = "出錯啦:" + ex.Message; } } }); workThread.Start(); }
public void Execute(object data) { try { lock (thisLock) { Bitmap clipImage = (Bitmap)data; ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); string strCodecToUse = null; ImageCodecInfo codecToUse = null; EncoderParameters encParams = null; switch (int.Parse(myOptions["SelectedFormat"])) { case 0: anigifTotalFrameNum = int.Parse(myOptions["AniGIFNumFrames"]); strCodecToUse = "AniGIF"; break; case 1: strCodecToUse = "BMP"; break; case 2: encParams = new EncoderParameters(2); encParams.Param[0] = new EncoderParameter(Encoder.Quality, long.Parse(myOptions["JPEGQuality"])); if (bool.Parse(myOptions["JPEGEncoding"])) { encParams.Param[1] = new EncoderParameter(Encoder.RenderMethod, (long)EncoderValue.RenderProgressive); } else { encParams.Param[1] = new EncoderParameter(Encoder.RenderMethod, (long)EncoderValue.RenderNonProgressive); } strCodecToUse = "JPEG"; break; case 3: strCodecToUse = "GIF"; break; case 4: switch (int.Parse(myOptions["TIFFCompression"])) { case 0: encParams = new EncoderParameters(1); encParams.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionNone); break; case 1: encParams = new EncoderParameters(2); encParams.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionCCITT3); encParams.Param[1] = new EncoderParameter(Encoder.ColorDepth, 1L); break; case 2: encParams = new EncoderParameters(2); encParams.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionCCITT4); encParams.Param[1] = new EncoderParameter(Encoder.ColorDepth, 1L); break; case 3: encParams = new EncoderParameters(1); encParams.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionLZW); break; case 4: encParams = new EncoderParameters(2); encParams.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionRle); encParams.Param[1] = new EncoderParameter(Encoder.ColorDepth, 1L); break; } strCodecToUse = "TIFF"; break; case 5: encParams = new EncoderParameters(1); if (bool.Parse(myOptions["PNGEncoding"])) { encParams.Param[0] = new EncoderParameter(Encoder.ScanMethod, (long)EncoderValue.ScanMethodInterlaced); } else { encParams.Param[0] = new EncoderParameter(Encoder.ScanMethod, (long)EncoderValue.ScanMethodNonInterlaced); } strCodecToUse = "PNG"; break; } if (!strCodecToUse.Equals("AniGIF")) { foreach (ImageCodecInfo codec in codecs) { if (codec.FormatDescription.Equals(strCodecToUse)) { codecToUse = codec; break; } } if (codecToUse != null) { string filename = myOptions["PrefixOutputName"] + fileNum + myOptions["SuffixOutputName"] + (codecToUse.FilenameExtension.Split(new char[] { ';' }))[0].Substring(1); clipImage.Save(filename, codecToUse, encParams); fileNum++; } } else { if (!aniGifEnc.IsStarted) { anigifFrameNum = 0; aniGifEnc.Start(myOptions["PrefixOutputName"] + fileNum + myOptions["SuffixOutputName"] + ".gif"); aniGifEnc.SetFrameRate(float.Parse(myOptions["AniGIFFrameRate"])); aniGifEnc.SetRepeat(int.Parse(myOptions["AniGIFRepeat"])); aniGifEnc.SetQuality(int.Parse(myOptions["AniGIFQuality"])); if (!myOptions["AniGIFTrasparent"].Equals("NULL")) { aniGifEnc.SetTransparent(Color.FromArgb(int.Parse(myOptions["AniGIFTrasparent"]))); } } aniGifEnc.AddFrame((Image)clipImage); anigifFrameNum++; MessageBox.Show("Frame " + anigifFrameNum.ToString() + " of " + anigifTotalFrameNum + " added.", "AniGIF Creation", MessageBoxButtons.OK, MessageBoxIcon.Information); if (anigifFrameNum >= anigifTotalFrameNum) { aniGifEnc.Finish(); fileNum++; } } } } catch (System.Runtime.InteropServices.ExternalException ee) { MessageBox.Show("Error writing file.\n" + ee.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (FormatException fe) { MessageBox.Show("Error parsing the configuration file.\n" + fe.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private async void Encode(ProjectInfo project, int id, Parameters param, CancellationTokenSource tokenSource) { var processing = this.DispatcherStringResource("Encoder.Processing"); var listFrames = project.Frames; try { switch (param.Type) { case Export.Gif: #region Gif 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++) { encoder.AddFrame(listFrames[i].FullPath, project.FrameSize, 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) { encoder.SetTransparent(param.DummyColor.Value); 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 var bitmapAux = new Bitmap(frame.FullPath); encoder.SetDelay(frame.Delay); encoder.AddFrame(bitmapAux, project.FrameSize.X, project.FrameSize.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].FullPath); 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.FullPath + "'"); concat.AppendLine("duration " + (frame.Delay / 1000d).ToString(CultureInfo.InvariantCulture)); } var concatPath = Path.GetDirectoryName(listFrames[0].FullPath) ?? 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].FullPath, 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 = $"Result:\n\r{Marshal.GetLastWin32Error()}" } } ; #endregion break; default: throw new Exception("Undefined Gif encoder type"); } #endregion break; case Export.Apng: #region Apng switch (param.ApngEncoder) { case ApngEncoderType.ScreenToGif: { #region Encoding using (var stream = new MemoryStream()) { var frameCount = listFrames.Count; using (var encoder = new Apng(stream, frameCount, param.RepeatCount)) { for (var i = 0; i < listFrames.Count; i++) { encoder.AddFrame(listFrames[i].FullPath, project.FrameSize, 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 break; } case ApngEncoderType.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.FullPath + "'"); concat.AppendLine("duration " + (frame.Delay / 1000d).ToString(CultureInfo.InvariantCulture)); } var concatPath = Path.GetDirectoryName(listFrames[0].FullPath) ?? 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.RepeatCount, 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 apng with FFmpeg.") { HelpLink = $"Command:\n\r{param.Command}\n\rResult:\n\r{str}" } } ; #endregion break; } } #endregion break; case Export.Video: #region Video switch (param.VideoEncoder) { case VideoEncoderType.AviStandalone: #region Avi Standalone var image = listFrames[0].FullPath.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.FullPath.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.FullPath + "'"); concat.AppendLine("duration " + (frame.Delay / 1000d).ToString(CultureInfo.InvariantCulture)); } var concatPath = Path.GetDirectoryName(listFrames[0].FullPath) ?? 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 Execute commands #if !UWP 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); } } #endif #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].FullPath); 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(); } }
// 感谢ok群群友 yuanyilvhua(QQ:4570848**)提供测试电脑,以修复之前存在的高分屏下的bug :-) private void button2_Click(object sender, EventArgs e) { PowerPoint.Selection sel = app.ActiveWindow.Selection; if (sel.Type == PowerPoint.PpSelectionType.ppSelectionSlides && sel.SlideRange.Count > 1) { PowerPoint.Slides slides = app.ActivePresentation.Slides; PowerPoint.SlideRange srange = sel.SlideRange; int scount = srange.Count; float wp = app.ActivePresentation.PageSetup.SlideWidth; float hp = app.ActivePresentation.PageSetup.SlideHeight; int pw = Properties.Settings.Default.pwidth; int h2 = (int)(pw * hp / wp); string name = app.ActivePresentation.Name; if (name.Contains(".pptx")) { name = name.Replace(".pptx", ""); } if (name.Contains(".ppt")) { name = name.Replace(".ppt", ""); } string cPath = app.ActivePresentation.Path + @"\" + name + @" 的GIF图\"; if (!Directory.Exists(cPath)) { Directory.CreateDirectory(cPath); } System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(cPath); int k = dir.GetFiles().Length + 1; string gpath = cPath + name + "_" + k + ".gif"; int time = int.Parse(textBox1.Text.Trim()); int[] index = new int[srange.Count]; for (int i = 1; i <= srange.Count; i++) { index[i - 1] = srange[i].SlideIndex; } if (index[0] > index[1]) { Array.Sort(index); } sel.Unselect(); slides.Range(index).Select(); List <string> path = new List <string>(); for (int i = 1; i <= scount; i++) { PowerPoint.Slide nslide = slides[index[i - 1]]; string cPath2 = cPath + name + "_" + k + ".jpg"; nslide.Export(cPath2, "jpg"); path.Add(cPath2); k = k + 1; } AnimatedGifEncoder gif = new AnimatedGifEncoder(); gif.Start(gpath); gif.SetDelay(time); if (checkBox1.Checked) { gif.SetRepeat(0); } else { gif.SetRepeat(-1); } Bitmap bmp = null; Graphics g = null; for (int j = 0; j < scount; j++) { Image spic = Image.FromFile(path[j]); if (j == 0) { bmp = new Bitmap(spic.Width, spic.Height); bmp.SetResolution(spic.HorizontalResolution, spic.VerticalResolution); g = Graphics.FromImage(bmp); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; } g.Clear(panel1.BackColor); g.DrawImage(spic, 0, 0); gif.AddFrame(bmp); spic.Dispose(); File.Delete(path[j]); } gif.Finish(); g.Dispose(); bmp.Dispose(); if (!checkBox2.Checked) { System.Diagnostics.Process.Start("Explorer.exe", cPath); } else { int n = srange[1].SlideNumber; PowerPoint.Shape nshape = slides[n].Shapes.AddPicture(gpath, Office.MsoTriState.msoFalse, Office.MsoTriState.msoTrue, -pw, 0, pw, h2); if (pw > app.ActivePresentation.PageSetup.SlideWidth) { nshape.LockAspectRatio = Office.MsoTriState.msoTrue; nshape.Width = app.ActivePresentation.PageSetup.SlideWidth; nshape.Left = 0; nshape.Top = 0; } nshape.Select(); File.Delete(gpath); if (dir.GetFiles().Length == 0) { Directory.Delete(cPath, true); } } } else if (sel.Type == PowerPoint.PpSelectionType.ppSelectionShapes) { PowerPoint.Slide slide = app.ActiveWindow.View.Slide; PowerPoint.ShapeRange range = sel.ShapeRange; if (sel.HasChildShapeRange) { range = sel.ChildShapeRange; } int count = range.Count; if (count > 1) { string name = app.ActivePresentation.Name; if (name.Contains(".pptx")) { name = name.Replace(".pptx", ""); } if (name.Contains(".ppt")) { name = name.Replace(".ppt", ""); } string cPath = app.ActivePresentation.Path + @"\" + name + @" 的GIF图\"; if (!Directory.Exists(cPath)) { Directory.CreateDirectory(cPath); } System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(cPath); int k = dir.GetFiles().Length + 1; int time = int.Parse(textBox1.Text.Trim()); string gpath = cPath + name + "_" + k + ".gif"; List <int> w = new List <int>(); List <int> h = new List <int>(); List <string> path = new List <string>(); Bitmap spic = null; float xs = 0; float ys = 0; for (int i = 1; i <= count; i++) { PowerPoint.Shape pic = range[i]; pic.Export(cPath + name + "_" + k + ".png", PowerPoint.PpShapeFormat.ppShapeFormatPNG); spic = new Bitmap(cPath + name + "_" + k + ".png"); w.Add(spic.Width); h.Add(spic.Height); if (xs == 0) { xs = spic.HorizontalResolution; ys = spic.VerticalResolution; } spic.Dispose(); path.Add(cPath + name + "_" + k + ".png"); k = k + 1; } int wmax = w.Max(); int hmax = h.Max(); Bitmap bmp = new Bitmap(wmax, hmax); bmp.SetResolution(xs, ys); Graphics g = Graphics.FromImage(bmp); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; AnimatedGifEncoder gif = new AnimatedGifEncoder(); gif.Start(gpath); gif.SetDelay(time); if (checkBox1.Checked) { gif.SetRepeat(0); } else { gif.SetRepeat(-1); } if (checkBox4.Checked) { gif.SetQuality(300); gif.SetTransparent(panel1.BackColor); } for (int j = 0; j < count; j++) { spic = new Bitmap(path[j]); g.Clear(panel1.BackColor); g.DrawImage(spic, (bmp.Width - spic.Width) / 2, (bmp.Height - spic.Height) / 2); gif.AddFrame(bmp); spic.Dispose(); File.Delete(path[j]); } gif.Finish(); g.Dispose(); bmp.Dispose(); if (!checkBox2.Checked) { System.Diagnostics.Process.Start("Explorer.exe", cPath); } else { PowerPoint.Shape nshape = slide.Shapes.AddPicture(gpath, Office.MsoTriState.msoFalse, Office.MsoTriState.msoTrue, -wmax, 0, wmax, hmax); nshape.Select(); //File.Delete(cPath + name + "_" + k + ".gif"); //if (dir.GetFiles().Length == 0) //{ // Directory.Delete(cPath, true); //} } } else { MessageBox.Show("请选中多张图片"); } } else { MessageBox.Show("请选中多张图片或幻灯片页面"); } }
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(); } }
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(); } }