protected override async Task <bool> Start(string tempInputFolderPath, string tempOutputFolderPath, string waifu2xCaffePath, string ffmpegPath) { _isRunning = true; _tempInputDir = tempInputFolderPath; this._taskState = "extracting animation frames"; InvokeTaskStateChanged(); var extractResult = await AnimationFrameExtractor.ExtractFrames(InputFilePath, tempInputFolderPath, () => this._canceled); if (this._canceled) { Logger.Information("Terminating frame extraction for {AnimationPath} since this task has been cancelled", this.InputFilePath); _isRunning = false; return(false); } if (extractResult == null) { Logger.Error("An error occurred while extracting the animation frames for {InputFilePath} using {TaskExtractorTypeName}", this.InputFilePath, AnimationFrameExtractor.GetType().Name); _isRunning = false; return(false); } TaskQueue tasks = new TaskQueue(); int numCompleted = 0; int numStarted = 0; Queue <string> remainingImages = new Queue <string>(extractResult.ExtractedFiles); var outputResolutionResolver = this.OutputResolutionResolver; ImageResolution inputImageResolution = null; ImageResolution previousResultOutputImageResolution = null; ImageResolution outputImageResolution; bool canUseOldFrames = false; using (var firstFrame = Image.FromFile(extractResult.ExtractedFiles.First())) { inputImageResolution = new ImageResolution { WidthInt = firstFrame.Width, HeightInt = firstFrame.Height }; outputImageResolution = outputResolutionResolver.Resolve(inputImageResolution); var resolvedResolutionSize = outputImageResolution.Width * outputImageResolution.Height / 1e6; var maxResolution = CompileProcess.MaxOutputResolutionMegapixels; if (resolvedResolutionSize > maxResolution) // Max output resolution is 8MP { Logger.Warning("Output resolution for animation frame {InputAnimation} is too high for the {ImageCompiler} animation frame compiler at {OutputResolutionMegapixels} megapixels, limiting output size to {MaxCompileResolutionMegapixels} megapixels.", InputFilePath, CompileProcess.GetType().Name, resolvedResolutionSize, maxResolution); outputResolutionResolver = new TargetPixelCountResolutionResolver(maxResolution * 1e6f); outputImageResolution = outputResolutionResolver.Resolve(inputImageResolution); } } // Take into account how output images are resized to have even dimensions after upscaling outputImageResolution.WidthInt += outputImageResolution.WidthInt % 2; outputImageResolution.HeightInt += outputImageResolution.HeightInt % 2; string firstPreviousResultOutputFramePath = Path.Combine(tempOutputFolderPath, Path.GetFileName(extractResult.ExtractedFiles.First())); if (File.Exists(firstPreviousResultOutputFramePath)) { previousResultOutputImageResolution = ImageHelper.GetImageResolution(firstPreviousResultOutputFramePath); } if (previousResultOutputImageResolution != null && previousResultOutputImageResolution.Distance(outputImageResolution) < 20) { canUseOldFrames = true; } List <string> outputImageFiles = new List <string>(); do { tasks.QueueLength = MaxWaifuTaskThreads; while (tasks.CanQueueTask && remainingImages.Count > 0) { this._taskState = $"{numCompleted}/{extractResult.ExtractedFiles.Count} frames complete, {MaxWaifuTaskThreads} at a time"; InvokeTaskStateChanged(); int frameIdx = ++numStarted; Logger.Debug("Starting frame {@FrameIndex}/{@NumFrames}", frameIdx, extractResult.ExtractedFiles.Count); string nextImgPath = remainingImages.Dequeue(); string fileName = Path.GetFileName(nextImgPath); string inputFramePath = Path.Combine(tempInputFolderPath, fileName); string outputFramePath = Path.Combine(tempOutputFolderPath, fileName); outputImageFiles.Add(outputFramePath); if (File.Exists(outputFramePath)) { Logger.Information("Found old output frame {FrameIndex} for {OutputAnimationPath}", frameIdx, OutputFilePath); if (!canUseOldFrames) { Logger.Information("Not using previous output frame {FrameIndex} for {OutputAnimationPath} since they do not match the current target resolution", frameIdx, this.OutputFilePath); Logger.Information("Current output resolution: {@CurrentOutputResolution}", outputImageResolution); Logger.Information("Previous output resolution: {@OldOutputResolution}", previousResultOutputImageResolution); File.Delete(outputFramePath); } else { var outputFrameRes = ImageHelper.GetImageResolution(outputFramePath); if (outputFrameRes != outputImageResolution) { Logger.Information("Using previous output frame {FrameIndex} for {OutputAnimationPath} but the image resolution is *slightly* off, resizing.."); ImageHelper.ResizeImage(outputFramePath, outputImageResolution); } numCompleted += 1; continue; } } var imageTask = new ImageTask(inputFramePath, outputFramePath, this.OutputResolutionResolver, this.ConvertMode); imageTask.TaskCompleted += (task) => { Interlocked.Increment(ref numCompleted); tasks.TryCompleteTask(task); }; imageTask.TaskFaulted += (task, reason) => { Logger.Debug("ImageTask failed for frame {@FrameIndex}/{@NumFrames} while upscaling {@InputFile} to {@OutputFile}", frameIdx, extractResult.ExtractedFiles.Count, inputFramePath, outputFramePath); }; imageTask.StartTask(tempInputFolderPath, tempOutputFolderPath, waifu2xCaffePath, ffmpegPath); tasks.TryQueueTask(imageTask); } numSubTasks = tasks.RunningTasks.Count; await Task.Delay(10); } while (numCompleted < extractResult.ExtractedFiles.Count && !_canceled); if (this._canceled) { Logger.Debug("Canceling frame upconversion"); foreach (var task in tasks.RunningTasks) { task.CancelTask(); } while (tasks.RunningTasks.Count > 0) { await Task.Delay(1); } this._isRunning = false; Logger.Debug("AnimationTask has been canceled"); return(false); } Logger.Information("Resizing output frames for {OutputAnimationPath} to have the same even dimensions"); foreach (var image in outputImageFiles) { var imageSize = ImageHelper.GetImageResolution(image); if (imageSize == outputImageResolution) { continue; } ImageHelper.ResizeImage(image, outputImageResolution); } this._taskState = $"Combining {extractResult.ExtractedFiles.Count} frames to {Path.GetExtension(OutputFilePath)}"; InvokeTaskStateChanged(); bool success = await CompileProcess.Run(InputFilePath, OutputFilePath, tempOutputFolderPath, extractResult.Fps); Cleanup(); _isRunning = false; return(success); }
internal override void GatherCompileInfo(App mainAppWithInfo) { ProjectProcess c; c = new ProjectProcess(); if (!CompileProcess.CanOperate(mainAppWithInfo.TempPath)) { string tempPath = Path.GetFullPath(Path.Combine(Path.GetTempPath(), "LuaSTG Editor/")); if (!Directory.Exists(tempPath)) { Directory.CreateDirectory(tempPath); } c.currentTempPath = tempPath; } else { c.currentTempPath = mainAppWithInfo.TempPath; } CompileProcess = c; c.projLuaPath = c.currentTempPath + "_editor_output.lua"; c.source = this; c.rootLuaPath = c.currentTempPath + "root.lua"; c.rootZipPackPath = c.currentTempPath + "pack.bat"; c.projPath = ""; if (!string.IsNullOrEmpty(DocPath)) { c.projPath = Path.GetDirectoryName(DocPath); } c.projMetaPath = DocPath + ".meta"; c.rootCode = "Include\'THlib.lua\'\nInclude\'_editor_output.lua\'"; c.zipExePath = mainAppWithInfo.ZipExecutablePath; c.luaSTGExePath = mainAppWithInfo.LuaSTGExecutablePath; if (!mainAppWithInfo.IsEXEPathSet) { throw new EXEPathNotSetException(); } c.projName = Path.GetFileNameWithoutExtension(RawDocName); //Find mod name foreach (TreeNode t in TreeNodes[0].Children) { if (t is ProjSettings) { if (!string.IsNullOrEmpty(t.attributes[0].AttrInput)) { c.projName = t.attributes[0].AttrInput; } break; } } c.luaSTGFolder = Path.GetDirectoryName(c.luaSTGExePath); c.targetZipPath = c.luaSTGFolder + "\\mod\\" + c.projName + ".zip"; foreach (IDocumentWithMeta idwm in referencedDoc) { if (idwm is PlainDocumentData pdd) { pdd.GatherCompileInfo(mainAppWithInfo); c.fileProcess.Add(pdd.CompileProcess as PartialProjectProcess); //MessageBox.Show(pdd.CompileProcess.GetType().ToString()); } else if (idwm is VirtualDoc vd) { string s = vd.DocPath; //try { DocumentData newDoc = GetNewByExtension(Path.GetExtension(s), -1 , Path.GetFileNameWithoutExtension(s), s, true); TreeNode t = newDoc.CreateNodeFromFile(s); newDoc.TreeNodes.Add(t); (newDoc as PlainDocumentData).parentProj = this; newDoc.GatherCompileInfo(mainAppWithInfo); c.fileProcess.Add(newDoc.CompileProcess as PartialProjectProcess); //MessageBox.Show(newDoc.CompileProcess.GetType().ToString()); } //catch { } } } }
public static void Run() { ConsoleColorState state = RC.ColorState; try { if (!Parser.HelpMode) { #region Setup if (VerboseSwitch.Defined) { RC.Verbosity = (ConsoleVerbosity)VerboseSwitch.Value; } else if (QuietSwitch.Defined) { RC.Verbosity = ConsoleVerbosity.Quiet; } if (WarningsAsErrors.Defined) { RC.WarningsAsErrors = WarningsAsErrors.Value; RC.ReportWarnings = WarningsAsErrors.Value; } RC.IsBuildMode = BuildSwitch.Defined; RC.WriteLine(ConsoleVerbosity.Normal, ""); RC.WriteLine(ConsoleVerbosity.Minimal, ConsoleThemeColor.TitleText, Title); //RC.WriteLine(ConsoleVerbosity.Minimal, ""); RC.ForegroundThemeColor = ConsoleThemeColor.Text; #endregion #region Check First Argument if (Helper.IsNullOrEmpty(PathString.Value)) { RC.WriteError(0101, Strings.Error_0101); return; } #endregion #region Create Process CompileProcess compressionProcess = new CompileProcess(); compressionProcess.LogToConsole = true; // ExecutableTypeMode if (ConsoleSwitch.Defined) { compressionProcess.ExecutableTypeLookupMode = ExecutableTypeMode.Explicit; compressionProcess.ExecutableType = ConsoleSwitch.Value ? ExecutableType.Console : ExecutableType.Forms; } else { compressionProcess.ExecutableTypeLookupMode = ExecutableTypeMode.Reflected; compressionProcess.ExecutableType = ExecutableType.Console; } #endregion #region Parse Optional Arguments #region ToolsCsv Argument Switch Arround if (ToolsCsv.Defined) { if (!OutputPath.Defined) { // If the output path argument has not been defined then manually set its value // to the value of the first argument. e.g. 'rug-tool.exe' OutputPath.Defined = true; OutputPath.SetValue(PathString.Value); } else { // if the output path argument has been defined then the fist argument must be an // additional .dll file so move the value to additional file list argument FileList.Value.Add(PathString.Value); } // Zero the value of the fist argument PathString.Reset(); if (compressionProcess.ExecutableTypeLookupMode != ExecutableTypeMode.Explicit) { compressionProcess.ExecutableTypeLookupMode = ExecutableTypeMode.Default; } } #endregion #region Additional Assembly Paths List <string> assemblyPaths = new List <string>(FileList.Value.Count + 1); if (PathString.Defined) { assemblyPaths.Add(PathString.Value); } foreach (object obj in FileList.Value) { assemblyPaths.Add(obj.ToString()); } compressionProcess.Assemblys.AddRange(assemblyPaths); compressionProcess.Compression.Files.AddRange(assemblyPaths); #endregion #region Output Path string output; if (OutputPath.Defined) { output = OutputPath.Value; } else if (PathString.Defined) { output = PathString.Value; } else { RC.WriteError(0104, Strings.Error_0104); return; } #endregion #region Initial Assembly Path string initial; if (PathString.Defined) { initial = PathString.Value; initial = "/" + initial.Substring(initial.LastIndexOf('\\') + 1); } else { initial = null; } compressionProcess.InitialAssemblyPath = initial; #endregion #region Icon Path string icon = ""; if (IconPath.Defined) { icon = IconPath.Value; } compressionProcess.IconFile = icon; #endregion #region AssemblyInfoPath string assemblyinfoFile = null; if (AssemblyInfoPath.Defined) { if (!File.Exists(AssemblyInfoPath.Value)) { RC.WriteError(0102, string.Format(Strings.Error_0102, AssemblyInfoPath.Value)); return; } assemblyinfoFile = AssemblyInfoPath.Value; } else if (!PathString.Defined) { RC.WriteError(0106, Strings.Error_0106); return; } compressionProcess.AssembyInfoSourceFilePath = assemblyinfoFile; #endregion #region Pass Arguments bool passArgs = compressionProcess.ExecutableType == ExecutableType.Console ? true : false; if (PassArgsSwitch.Defined) { passArgs = PassArgsSwitch.Value; } compressionProcess.PassArguments = passArgs; #endregion #region Decorate compressionProcess.Decorate = DecorateSwitch.Defined; #endregion #region Protect Zip compressionProcess.Compression.Protected = ProtectZipSwitch.Defined; compressionProcess.Compression.Password = ProtectZipSwitch.Value; #endregion #region Build Tools foreach (string toolString in ToolsCsv.Value) { int index = toolString.IndexOf(':'); if (index < 1) { RC.WriteError(0105, string.Format(Strings.Error_0105, toolString)); return; } string toolName = toolString.Substring(0, index); string toolPath = toolString.Substring(index + 1); compressionProcess.Tools.Add(toolName, toolPath); compressionProcess.Compression.Files.Add(toolPath); } #endregion #endregion #region Execute Bundle and Compile RC.ForegroundThemeColor = ConsoleThemeColor.Text; compressionProcess.Compression.CreatePackage(); #endregion if (compressionProcess.RunProcess(output)) { #region Print Size Summary RC.WriteLine(ConsoleVerbosity.Verbose, ConsoleThemeColor.TitleText, "\n\n" + Strings.Text_FinalSummary); RC.WriteLine(ConsoleThemeColor.SubText, " " + new string(ConsoleChars.SingleLines[1], 41)); Rug.Cmd.CmdHelper.WriteInfoToConsole(Strings.Text_UncompressedSize, CmdHelper.GetMemStringFromBytes(compressionProcess.InitialSize, true), RC.Theme[ConsoleThemeColor.Text]); if (compressionProcess.IconFileSize > 0) { Rug.Cmd.CmdHelper.WriteInfoToConsole(Strings.Text_IconFileSize, CmdHelper.GetMemStringFromBytes(compressionProcess.IconFileSize, true), RC.Theme[ConsoleThemeColor.Text]); Rug.Cmd.CmdHelper.WriteInfoToConsole(Strings.Text_TotalSize, CmdHelper.GetMemStringFromBytes(compressionProcess.InitialSize + compressionProcess.IconFileSize, true), RC.Theme[ConsoleThemeColor.Text]); } Rug.Cmd.CmdHelper.WriteInfoToConsole(Strings.Text_StartupOverhead, CmdHelper.GetMemStringFromBytes(compressionProcess.OverheadSize, true), RC.Theme[ConsoleThemeColor.Text]); ConsoleThemeColor compColor = ConsoleThemeColor.Text; if (compressionProcess.FinalFileSize < compressionProcess.TotalInitialFileSize / 2) { compColor = ConsoleThemeColor.TextGood; } else if (compressionProcess.FinalFileSize < (compressionProcess.TotalInitialFileSize / 4) * 3) { compColor = ConsoleThemeColor.SubTextGood; } else if ((compressionProcess.FinalFileSize >= ((compressionProcess.TotalInitialFileSize / 4) * 3)) && (compressionProcess.FinalFileSize < compressionProcess.TotalInitialFileSize)) { compColor = ConsoleThemeColor.SubTextNutral; } else if (compressionProcess.FinalFileSize == compressionProcess.TotalInitialFileSize) { compColor = ConsoleThemeColor.Text; } else if (compressionProcess.FinalFileSize > compressionProcess.TotalInitialFileSize) { compColor = ConsoleThemeColor.TextBad; } Rug.Cmd.CmdHelper.WriteInfoToConsole(Strings.Text_FinalSize, CmdHelper.GetMemStringFromBytes(compressionProcess.FinalFileSize, true), RC.Theme[compColor]); RC.WriteLine(ConsoleThemeColor.SubText, " " + new string(ConsoleChars.SingleLines[1], 41)); RC.Write(ConsoleVerbosity.Minimal, ConsoleThemeColor.TitleText, " " + Strings.Text_OverallCompression); #endregion if (compressionProcess.FinalFileSize > 0) { #region Print Final Success Message string valueString = ((100 - (((double)compressionProcess.FinalFileSize / (double)compressionProcess.TotalInitialFileSize) * 100.0)).ToString("N2") + "%"); RC.Write(ConsoleVerbosity.Minimal, ConsoleThemeColor.SubText, " :".PadRight(22 - valueString.Length, '.')); RC.WriteLine(ConsoleVerbosity.Minimal, compColor, valueString); int offset = 6; if (compColor == ConsoleThemeColor.TextBad) { offset += 3; RC.WriteLine(""); RC.WriteWarning(0103, " " + Strings.Error_0103); } if (RC.CanManipulateBuffer && (int)RC.Verbosity >= (int)ConsoleVerbosity.Normal) { Rug.Cmd.CmdHelper.WriteRuglandLogo(48, RC.CursorTop - offset, 3, 2, false, ConsoleShade.Opaque); } #endregion } else { #region The Final Size Is Invlaid So Print A Message RC.Write(ConsoleVerbosity.Minimal, ConsoleThemeColor.SubText, new string('.', 19 - Strings.Text_Invalid.Length)); RC.WriteLine(ConsoleVerbosity.Minimal, ConsoleThemeColor.ErrorColor1, Strings.Text_Invalid); #endregion } } } } catch (Exception ex) { RC.WriteException(0199, ex); } finally { #region Reset The Color State RC.ColorState = state; RC.WriteLine(ConsoleVerbosity.Minimal, ""); #endregion } }