├── .gitignore ├── Code ├── App.config ├── Costura32 │ └── DdsFileTypePlusIO_x86.dll ├── Costura64 │ └── DdsFileTypePlusIO_x64.dll ├── Cupscale.csproj ├── Cupscale.sln ├── CupscaleLogo1.ico ├── Data │ └── ModelData.cs ├── FFmpeg │ ├── FFmpeg.cs │ ├── FFmpegCommands.cs │ └── FFmpegStrings.cs ├── FodyWeavers.xml ├── FodyWeavers.xsd ├── Forms │ ├── AdvancedModelForm.Designer.cs │ ├── AdvancedModelForm.cs │ ├── AdvancedModelForm.resx │ ├── DependencyCheckerForm.Designer.cs │ ├── DependencyCheckerForm.cs │ ├── DependencyCheckerForm.resx │ ├── DialogForm.Designer.cs │ ├── DialogForm.cs │ ├── DialogForm.resx │ ├── InterpForm.Designer.cs │ ├── InterpForm.cs │ ├── InterpForm.resx │ ├── ModelComparisonForm.Designer.cs │ ├── ModelComparisonForm.cs │ ├── ModelComparisonForm.resx │ ├── ModelSelectForm.Designer.cs │ ├── ModelSelectForm.cs │ ├── ModelSelectForm.resx │ ├── MsgBox.Designer.cs │ ├── MsgBox.cs │ ├── MsgBox.resx │ ├── SettingsForm.Designer.cs │ ├── SettingsForm.cs │ └── SettingsForm.resx ├── IO │ ├── Config.cs │ ├── ConfigParser.cs │ ├── IOUtils.cs │ ├── Installer.cs │ └── Paths.cs ├── ImageUtils │ ├── Filters.cs │ ├── ImageOperations.cs │ ├── ImageProcessing.cs │ ├── ImgUtils.cs │ ├── MozJpeg.cs │ └── NvCompress.cs ├── Implementations │ ├── EsrganNcnn.cs │ ├── EsrganPytorch.cs │ ├── Implementation.cs │ ├── ImplementationBase.cs │ ├── Imps.cs │ └── RealEsrganNcnn.cs ├── Main │ ├── AdvancedModelSelection.cs │ ├── Dependencies.cs │ ├── EsrganData.cs │ ├── GeneralOutputHandler.cs │ ├── Logger.cs │ ├── MainForm.Designer.cs │ ├── MainForm.cs │ ├── MainForm.resx │ ├── PostProcessing.cs │ ├── PostProcessingQueue.cs │ ├── PreviewState.cs │ ├── Program.cs │ ├── Servers.cs │ └── Upscale.cs ├── OS │ ├── EmbeddedPython.cs │ ├── NcnnUtils.cs │ ├── NvApi.cs │ └── OSUtils.cs ├── Preview │ ├── ClipboardComparison.cs │ └── PreviewMerger.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Resources │ ├── 7za.exe │ ├── CupscaleLogo1.ico │ ├── baseline_fact_check_white_48dp.png │ ├── baseline_folder_open_white_48dp.png │ ├── baseline_photo_library_white_48dp.png │ ├── baseline_refresh_white_48dp.png │ ├── baseline_settings_white_48dp.png │ ├── discordIcoColored.png │ ├── ffmpeg-h264.exe │ ├── interp.png │ ├── modelCompare.png │ ├── patreon256pxColored.png │ ├── paypal256px.png │ ├── questmark.png │ └── shipped-files-version.txt ├── UI │ ├── BatchUpscaleUI.cs │ ├── Controls │ │ └── ModelCombox.cs │ ├── DialogQueue.cs │ ├── ExtensionMethods.cs │ ├── ModelComparisonTool.cs │ ├── PreviewUI.cs │ ├── UIHelpers.cs │ └── VideoUpscaleUI.cs └── app.manifest ├── Installer Files ├── av.7z ├── esrgan-ncnn.7z └── esrgan.7z ├── LICENSE ├── Media ├── baseline_settings_white_48dp.png ├── discordIcoColored.png └── patreon256pxColored.png └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /Code/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Code/Costura32/DdsFileTypePlusIO_x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Costura32/DdsFileTypePlusIO_x86.dll -------------------------------------------------------------------------------- /Code/Costura64/DdsFileTypePlusIO_x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Costura64/DdsFileTypePlusIO_x64.dll -------------------------------------------------------------------------------- /Code/Cupscale.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Cupscale 4 | False 5 | WinExe 6 | True 7 | net472 8 | True 9 | AnyCPU;x64;x86 10 | Debug;Release;NoNCNN 11 | 12 | 13 | Preview 14 | True 15 | CupscaleLogo1.ico 16 | app.manifest 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Never 28 | 29 | 30 | Never 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | all 41 | runtime; build; native; contentfiles; analyzers; buildtransitive 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll 58 | 59 | 60 | C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.IO.Compression.FileSystem\v4.0_4.0.0.0__b77a5c561934e089\System.IO.Compression.FileSystem.dll 61 | 62 | 63 | 64 | 65 | Form 66 | 67 | 68 | True 69 | True 70 | Resources.resx 71 | 72 | 73 | True 74 | True 75 | Settings.settings 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | PublicResXFileCodeGenerator 85 | Resources.Designer.cs 86 | 87 | 88 | 89 | 90 | SettingsSingleFileGenerator 91 | Settings.Designer.cs 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | Never 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /Code/Cupscale.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30413.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cupscale", "Cupscale.csproj", "{CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | NoNCNN|Any CPU = NoNCNN|Any CPU 14 | NoNCNN|x64 = NoNCNN|x64 15 | NoNCNN|x86 = NoNCNN|x86 16 | Release|Any CPU = Release|Any CPU 17 | Release|x64 = Release|x64 18 | Release|x86 = Release|x86 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Debug|x64.ActiveCfg = Debug|x64 24 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Debug|x64.Build.0 = Debug|x64 25 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Debug|x86.ActiveCfg = Debug|x86 26 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Debug|x86.Build.0 = Debug|x86 27 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.NoNCNN|Any CPU.ActiveCfg = NoNCNN|Any CPU 28 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.NoNCNN|Any CPU.Build.0 = NoNCNN|Any CPU 29 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.NoNCNN|x64.ActiveCfg = NoNCNN|x64 30 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.NoNCNN|x64.Build.0 = NoNCNN|x64 31 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.NoNCNN|x86.ActiveCfg = NoNCNN|x86 32 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.NoNCNN|x86.Build.0 = NoNCNN|x86 33 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Release|x64.ActiveCfg = Release|x64 36 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Release|x64.Build.0 = Release|x64 37 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Release|x86.ActiveCfg = Release|x86 38 | {CB003524-BE0F-42E5-BDE2-A98DCE51CE0A}.Release|x86.Build.0 = Release|x86 39 | EndGlobalSection 40 | GlobalSection(SolutionProperties) = preSolution 41 | HideSolutionNode = FALSE 42 | EndGlobalSection 43 | GlobalSection(ExtensibilityGlobals) = postSolution 44 | SolutionGuid = {7687F542-1BB8-46CE-B661-A7F24E6F1BB4} 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /Code/CupscaleLogo1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/CupscaleLogo1.ico -------------------------------------------------------------------------------- /Code/Data/ModelData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Cupscale.Data 9 | { 10 | struct ModelData 11 | { 12 | public string model1Name; 13 | public string model2Name; 14 | public string model1Path; 15 | public string model2Path; 16 | public enum ModelMode { Single, Interp, Chain, Advanced } 17 | public ModelMode mode; 18 | public int interp; 19 | 20 | public ModelData(string model1, string model2, ModelMode modelMode, int interpolation = 0) 21 | { 22 | model1Name = Path.GetFileNameWithoutExtension(model1); 23 | model2Name = Path.GetFileNameWithoutExtension(model2); 24 | model1Path = model1; 25 | model2Path = model2; 26 | mode = modelMode; 27 | interp = interpolation; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Code/FFmpeg/FFmpeg.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.IO; 2 | using Cupscale.OS; 3 | using Cupscale.UI; 4 | using System.Diagnostics; 5 | using System.Threading.Tasks; 6 | 7 | namespace Cupscale 8 | { 9 | class FFmpeg 10 | { 11 | public static string lastOutputFfmpeg; 12 | 13 | public static async Task Run(string args) 14 | { 15 | lastOutputFfmpeg = ""; 16 | Process ffmpeg = OsUtils.NewProcess(true); 17 | ffmpeg.StartInfo.Arguments = $"/C cd /D {Paths.binPath.Wrap()} & ffmpeg.exe -hide_banner -loglevel warning -y -stats {args}"; 18 | Logger.Log("Running ffmpeg..."); 19 | Logger.Log("cmd.exe " + ffmpeg.StartInfo.Arguments); 20 | ffmpeg.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); 21 | ffmpeg.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler); 22 | ffmpeg.Start(); 23 | ffmpeg.BeginOutputReadLine(); 24 | ffmpeg.BeginErrorReadLine(); 25 | 26 | while (!ffmpeg.HasExited) 27 | await Task.Delay(100); 28 | 29 | Logger.Log("Done running ffmpeg."); 30 | } 31 | 32 | static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 33 | { 34 | string line = outLine.Data; 35 | if (outLine == null || line == null) return; 36 | lastOutputFfmpeg = lastOutputFfmpeg + line + "\n"; 37 | Logger.Log("[FFmpeg] " + line); 38 | 39 | if (line.ToLower().Contains("error")) 40 | Program.ShowMessage("FFmpeg Error:\n\n" + line); 41 | } 42 | 43 | public static async Task RunGifski (string args) 44 | { 45 | Process ffmpeg = OsUtils.NewProcess(true); 46 | ffmpeg.StartInfo.Arguments = $"/C cd /D {Paths.binPath.Wrap()} & gifski.exe {args}"; 47 | Logger.Log("Running gifski..."); 48 | Logger.Log("cmd.exe " + ffmpeg.StartInfo.Arguments); 49 | ffmpeg.OutputDataReceived += new DataReceivedEventHandler(OutputHandlerGifski); 50 | ffmpeg.ErrorDataReceived += new DataReceivedEventHandler(OutputHandlerGifski); 51 | ffmpeg.Start(); 52 | ffmpeg.BeginOutputReadLine(); 53 | ffmpeg.BeginErrorReadLine(); 54 | 55 | while (!ffmpeg.HasExited) 56 | await Task.Delay(100); 57 | 58 | Logger.Log("Done running gifski."); 59 | } 60 | 61 | static void OutputHandlerGifski (object sendingProcess, DataReceivedEventArgs outLine) 62 | { 63 | string line = outLine.Data; 64 | if (outLine == null || line == null) return; 65 | Logger.Log("[gifski] " + line); 66 | 67 | if (line.ToLower().Contains("error")) 68 | Program.ShowMessage("Gifski Error:\n\n" + line); 69 | } 70 | 71 | public static string RunAndGetOutput (string args) 72 | { 73 | Process ffmpeg = OsUtils.NewProcess(true); 74 | ffmpeg.StartInfo.Arguments = $"/C cd /D {Paths.binPath.Wrap()} & ffmpeg.exe -hide_banner -y -stats {args}"; 75 | ffmpeg.Start(); 76 | ffmpeg.WaitForExit(); 77 | string output = ffmpeg.StandardOutput.ReadToEnd(); 78 | string err = ffmpeg.StandardError.ReadToEnd(); 79 | 80 | if (!string.IsNullOrWhiteSpace(err)) 81 | output = output + "\n" + err; 82 | 83 | return output; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Code/FFmpeg/FFmpegStrings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Cupscale 8 | { 9 | class FFmpegStrings 10 | { 11 | public static string hdrFilter = @"-vf select=gte(n\,%frNum%),zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Code/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Code/FodyWeavers.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks 13 | 14 | 15 | 16 | 17 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. 18 | 19 | 20 | 21 | 22 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks. 23 | 24 | 25 | 26 | 27 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks. 28 | 29 | 30 | 31 | 32 | The order of preloaded assemblies, delimited with line breaks. 33 | 34 | 35 | 36 | 37 | 38 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. 39 | 40 | 41 | 42 | 43 | Controls if .pdbs for reference assemblies are also embedded. 44 | 45 | 46 | 47 | 48 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. 49 | 50 | 51 | 52 | 53 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. 54 | 55 | 56 | 57 | 58 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. 59 | 60 | 61 | 62 | 63 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. 64 | 65 | 66 | 67 | 68 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | 69 | 70 | 71 | 72 | 73 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. 74 | 75 | 76 | 77 | 78 | A list of unmanaged 32 bit assembly names to include, delimited with |. 79 | 80 | 81 | 82 | 83 | A list of unmanaged 64 bit assembly names to include, delimited with |. 84 | 85 | 86 | 87 | 88 | The order of preloaded assemblies, delimited with |. 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. 97 | 98 | 99 | 100 | 101 | A comma-separated list of error codes that can be safely ignored in assembly verification. 102 | 103 | 104 | 105 | 106 | 'false' to turn off automatic generation of the XML Schema file. 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /Code/Forms/AdvancedModelForm.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.Main; 2 | using Cupscale.UI; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Drawing; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | using System.Windows.Forms; 13 | using static Cupscale.Main.AdvancedModelSelection; 14 | 15 | namespace Cupscale.Forms 16 | { 17 | public partial class AdvancedModelForm : Form 18 | { 19 | 20 | public AdvancedModelForm() 21 | { 22 | InitializeComponent(); 23 | Show(); 24 | } 25 | 26 | private void entry1Model1Interp_TextChanged(object sender, EventArgs e) 27 | { 28 | int input = entry1Model1Interp.GetInt().Clamp(0, 100); 29 | entry1Model1Interp.Text = input.ToString(); 30 | e1m1i = input; 31 | e1m2i = 100 - e1m1i; 32 | entry1Model2Interp.Text = e1m2i.ToString(); 33 | } 34 | 35 | private void entry2Model1Interp_TextChanged(object sender, EventArgs e) 36 | { 37 | int input = entry2Model1Interp.GetInt().Clamp(0, 100); 38 | entry2Model1Interp.Text = input.ToString(); 39 | e2m1i = input; 40 | e2m2i = 100 - e2m1i; 41 | entry2Model2Interp.Text = e2m2i.ToString(); 42 | } 43 | 44 | private void entry3Model1Interp_TextChanged(object sender, EventArgs e) 45 | { 46 | int input = entry3Model1Interp.GetInt().Clamp(0, 100); 47 | entry3Model1Interp.Text = input.ToString(); 48 | e3m1i = input; 49 | e3m2i = 100 - e3m1i; 50 | entry3Model2Interp.Text = e3m2i.ToString(); 51 | } 52 | 53 | private void entry1Model1_Click(object sender, EventArgs e) 54 | { 55 | using (var modelForm = new ModelSelectForm(entry1Model1, 0)) 56 | { 57 | if (modelForm.ShowDialog() == DialogResult.OK) 58 | e1m1 = modelForm.selectedModel; 59 | } 60 | } 61 | 62 | private void entry1Model2_Click(object sender, EventArgs e) 63 | { 64 | using (var modelForm = new ModelSelectForm(entry1Model2, 0)) 65 | { 66 | if (modelForm.ShowDialog() == DialogResult.OK) 67 | e1m2 = modelForm.selectedModel; 68 | } 69 | } 70 | 71 | private void entry2Model1_Click(object sender, EventArgs e) 72 | { 73 | using (var modelForm = new ModelSelectForm(entry2Model1, 0)) 74 | { 75 | if (modelForm.ShowDialog() == DialogResult.OK) 76 | e2m1 = modelForm.selectedModel; 77 | } 78 | } 79 | 80 | private void entry2Model2_Click(object sender, EventArgs e) 81 | { 82 | using (var modelForm = new ModelSelectForm(entry2Model2, 0)) 83 | { 84 | if (modelForm.ShowDialog() == DialogResult.OK) 85 | e2m2 = modelForm.selectedModel; 86 | } 87 | } 88 | 89 | private void entry3Model1_Click(object sender, EventArgs e) 90 | { 91 | using (var modelForm = new ModelSelectForm(entry3Model1, 0)) 92 | { 93 | if (modelForm.ShowDialog() == DialogResult.OK) 94 | e3m1 = modelForm.selectedModel; 95 | } 96 | } 97 | 98 | private void entry3Model2_Click(object sender, EventArgs e) 99 | { 100 | using (var modelForm = new ModelSelectForm(entry3Model2, 0)) 101 | { 102 | if (modelForm.ShowDialog() == DialogResult.OK) 103 | e3m2 = modelForm.selectedModel; 104 | } 105 | } 106 | 107 | private void cancelBtn_Click(object sender, EventArgs e) 108 | { 109 | e1m1 = null; 110 | e1m2 = null; 111 | e2m1 = null; 112 | e2m2 = null; 113 | e3m1 = null; 114 | e3m2 = null; 115 | Close(); 116 | } 117 | 118 | private void confirmBtn_Click(object sender, EventArgs e) 119 | { 120 | Logger.Log("Advanced Model Arg: " + GetArg()); 121 | SavePreset("lastUsed"); 122 | Close(); 123 | } 124 | 125 | private void AdvancedModelForm_Load(object sender, EventArgs e) 126 | { 127 | if (!LoadPreset("lastUsed")) 128 | return; 129 | 130 | ChangeButtonText(entry1Model1, GetModelName(e1m1)); 131 | entry1Model1Interp.Text = e1m1i.ToString(); 132 | ChangeButtonText(entry1Model2, GetModelName(e1m2)); 133 | entry1Model2Interp.Text = e1m2i.ToString(); 134 | 135 | ChangeButtonText(entry2Model1, GetModelName(e2m1)); 136 | entry2Model1Interp.Text = e2m1i.ToString(); 137 | ChangeButtonText(entry2Model2, GetModelName(e2m2)); 138 | entry2Model2Interp.Text = e3m2i.ToString(); 139 | 140 | ChangeButtonText(entry3Model1, GetModelName(e3m1)); 141 | entry3Model1Interp.Text = e3m1i.ToString(); 142 | ChangeButtonText(entry3Model2, GetModelName(e3m2)); 143 | entry3Model2Interp.Text = e3m2i.ToString(); 144 | } 145 | 146 | void ChangeButtonText (Button btn, string newText) 147 | { 148 | if (!string.IsNullOrWhiteSpace(newText)) 149 | btn.Text = newText; 150 | 151 | } 152 | 153 | string GetModelName (string path) 154 | { 155 | return Path.GetFileNameWithoutExtension(path); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Code/Forms/AdvancedModelForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Select the models you want to interpolate/chain. 122 | You don't need to fill out all model fields - empty ones will be ignored. 123 | This way you can, for example, chain two interpolated models, or three single models, or even three interpolated models. 124 | Entry 1 will be chained with Entry 2 and then Entry 3, but you can also just chain two models by leaving Entry 3 empty. 125 | 126 | 127 | -------------------------------------------------------------------------------- /Code/Forms/DependencyCheckerForm.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.Main; 2 | using Cupscale.OS; 3 | using Cupscale.UI; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.Data; 8 | using System.Diagnostics; 9 | using System.Drawing; 10 | using System.IO; 11 | using System.Linq; 12 | using System.Management; 13 | using System.Text; 14 | using System.Threading.Tasks; 15 | using System.Windows.Forms; 16 | 17 | namespace Cupscale.Forms 18 | { 19 | public partial class DependencyCheckerForm : Form 20 | { 21 | Stopwatch sw = new Stopwatch(); 22 | 23 | bool gpuAvail; 24 | bool nvGpuAvail; 25 | bool sysPyAvail; 26 | bool embedPyAvail; 27 | bool torchAvail; 28 | bool cv2Avail; 29 | 30 | public DependencyCheckerForm(bool openPyInstaller = false, bool startPyInstall = false) 31 | { 32 | InitializeComponent(); 33 | 34 | if (openPyInstaller) 35 | tabList1.SelectedIndex = 1; 36 | 37 | if (openPyInstaller && startPyInstall) 38 | installBtn_Click(null, null); 39 | } 40 | 41 | private async void DependencyCheckerForm_Load(object sender, EventArgs e) 42 | { 43 | 44 | } 45 | 46 | public async Task Refresh () 47 | { 48 | if (sw.ElapsedMilliseconds < 1000 && sw.ElapsedMilliseconds != 0) 49 | { 50 | Logger.Log($"[DepCheck] Skipping refresh - Only {sw.ElapsedMilliseconds}ms have passed since last refresh!"); 51 | return; 52 | } 53 | 54 | sw.Restart(); 55 | Logger.Log("[DepCheck] Refreshing..."); 56 | 57 | gpuAvail = false; 58 | nvGpuAvail = false; 59 | sysPyAvail = false; 60 | embedPyAvail = false; 61 | torchAvail = false; 62 | cv2Avail = false; 63 | 64 | SetChecking(gpu); 65 | 66 | if (Dependencies.HasGpu()) 67 | { 68 | SetGreen(gpu, "Available"); 69 | gpuAvail = true; 70 | } 71 | else 72 | { 73 | SetRed(gpu); 74 | } 75 | 76 | await Task.Delay(10); 77 | SetChecking(nvGpu); 78 | 79 | if (NvApi.gpuList.Count > 0) 80 | { 81 | string gpuText = NvApi.GetFirstGpuName().Replace("NVIDIA ", "").Replace("AMD ", "").Replace("GeForce ", ""); 82 | Logger.Log("[DepCheck] First GPU Name: " + gpuText); 83 | 84 | if (NvApi.gpuList.Count > 1) 85 | gpuText = $"{gpuText} + {NvApi.gpuList.Count - 1}"; 86 | 87 | SetGreen(nvGpu, gpuText); 88 | nvGpuAvail = true; 89 | } 90 | else 91 | { 92 | SetRed(nvGpu); 93 | } 94 | 95 | await Task.Delay(10); 96 | 97 | SetChecking(sysPython); 98 | string sysPyVer = Dependencies.GetSysPyVersion(); 99 | 100 | if (!string.IsNullOrWhiteSpace(sysPyVer) && !sysPyVer.ToLower().Contains("not found") && sysPyVer.Length <= 35) 101 | { 102 | SetGreen(sysPython, sysPyVer); 103 | sysPyAvail = true; 104 | } 105 | else 106 | { 107 | SetRed(sysPython); 108 | } 109 | 110 | await Task.Delay(10); 111 | 112 | SetChecking(embedPython); 113 | string embedPyVer = Dependencies.GetEmbedPyVersion(); 114 | 115 | if (!string.IsNullOrWhiteSpace(embedPyVer) && !embedPyVer.ToLower().Contains("not found") && embedPyVer.Length <= 35) 116 | { 117 | SetGreen(embedPython, embedPyVer); 118 | embedPyAvail = true; 119 | } 120 | else 121 | { 122 | SetRed(embedPython); 123 | } 124 | 125 | if (!sysPyAvail && embedPyAvail) 126 | SetGrey(sysPython, "Not Needed"); 127 | 128 | if (!embedPyAvail&& sysPyAvail) 129 | SetGrey(embedPython, "Not Needed"); 130 | 131 | await Task.Delay(10); 132 | 133 | SetChecking(torch); 134 | string torchVer = Dependencies.GetPytorchVer(); 135 | 136 | if (!string.IsNullOrWhiteSpace(torchVer) && torchVer.Length <= 35) 137 | { 138 | SetGreen(torch, torchVer); 139 | torchAvail = true; 140 | } 141 | else 142 | { 143 | SetRed(torch); 144 | } 145 | 146 | await Task.Delay(10); 147 | 148 | SetChecking(cv2); 149 | string cv2Ver = Dependencies.GetOpenCvVer(); 150 | 151 | if (!string.IsNullOrWhiteSpace(cv2Ver) && !cv2Ver.ToLower().Contains("ModuleNotFoundError") && cv2Ver.Length <= 35) 152 | { 153 | SetGreen(cv2, cv2Ver); 154 | cv2Avail = true; 155 | } 156 | else 157 | { 158 | SetRed(cv2); 159 | } 160 | 161 | RefreshAvailOptions(); 162 | } 163 | 164 | void RefreshAvailOptions () 165 | { 166 | bool hasAnyPy = sysPyAvail || embedPyAvail; 167 | bool hasPyDepends = torchAvail && cv2Avail; 168 | 169 | if(hasAnyPy && hasPyDepends) 170 | { 171 | SetGreen(cpuUpscaling, "Available"); 172 | 173 | if (nvGpuAvail) 174 | SetGreen(cudaUpscaling, "Available"); 175 | else 176 | SetRed(cudaUpscaling, "No Nvidia GPU"); 177 | } 178 | else 179 | { 180 | SetRed(cpuUpscaling, "Missing Dependencies"); 181 | SetRed(cudaUpscaling, "Missing Dependencies"); 182 | } 183 | 184 | if(gpuAvail) 185 | SetGreen(ncnnUpscaling, "Available"); 186 | else 187 | SetRed(ncnnUpscaling, "Not Available"); 188 | } 189 | 190 | void SetChecking(Label l) 191 | { 192 | l.Text = "Checking..."; 193 | l.ForeColor = Color.Silver; 194 | } 195 | 196 | void SetGreen(Label l, string t) 197 | { 198 | l.Text = t; 199 | l.ForeColor = Color.Lime; 200 | } 201 | 202 | void SetRed (Label l, string t = "Not Found") 203 | { 204 | l.Text = t; 205 | l.ForeColor = Color.Red; 206 | } 207 | 208 | void SetGrey(Label l, string t = "Not Found") 209 | { 210 | l.Text = t; 211 | l.ForeColor = Color.Gray; 212 | } 213 | 214 | private async void label8_VisibleChanged(object sender, EventArgs e) 215 | { 216 | if (!label8.Visible) 217 | return; 218 | 219 | await Task.Delay(100); 220 | await Refresh(); 221 | } 222 | 223 | private async void installBtn_Click(object sender, EventArgs e) 224 | { 225 | await EmbeddedPython.Download(installerLogBox, installBtn); 226 | } 227 | 228 | private void DependencyCheckerForm_FormClosing(object sender, FormClosingEventArgs e) 229 | { 230 | if(!installBtn.Enabled) 231 | e.Cancel = true; 232 | } 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /Code/Forms/DependencyCheckerForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Code/Forms/DialogForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Cupscale.Forms 2 | { 3 | partial class DialogForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DialogForm)); 32 | this.mainLabel = new System.Windows.Forms.Label(); 33 | this.panel1 = new System.Windows.Forms.Panel(); 34 | this.panel1.SuspendLayout(); 35 | this.SuspendLayout(); 36 | // 37 | // mainLabel 38 | // 39 | this.mainLabel.Dock = System.Windows.Forms.DockStyle.Fill; 40 | this.mainLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 41 | this.mainLabel.ForeColor = System.Drawing.Color.White; 42 | this.mainLabel.Location = new System.Drawing.Point(0, 0); 43 | this.mainLabel.Name = "mainLabel"; 44 | this.mainLabel.Size = new System.Drawing.Size(498, 78); 45 | this.mainLabel.TabIndex = 0; 46 | this.mainLabel.Text = "Dialog Text Here..."; 47 | this.mainLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 48 | // 49 | // panel1 50 | // 51 | this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 52 | this.panel1.Controls.Add(this.mainLabel); 53 | this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; 54 | this.panel1.Location = new System.Drawing.Point(0, 0); 55 | this.panel1.Name = "panel1"; 56 | this.panel1.Size = new System.Drawing.Size(500, 80); 57 | this.panel1.TabIndex = 1; 58 | // 59 | // DialogForm 60 | // 61 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 62 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 63 | this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(48)))), ((int)(((byte)(48)))), ((int)(((byte)(48))))); 64 | this.ClientSize = new System.Drawing.Size(500, 80); 65 | this.Controls.Add(this.panel1); 66 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; 67 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 68 | this.Name = "DialogForm"; 69 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 70 | this.Text = "DialogForm"; 71 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.DialogForm_FormClosing); 72 | this.panel1.ResumeLayout(false); 73 | this.ResumeLayout(false); 74 | 75 | } 76 | 77 | #endregion 78 | 79 | private System.Windows.Forms.Label mainLabel; 80 | private System.Windows.Forms.Panel panel1; 81 | } 82 | } -------------------------------------------------------------------------------- /Code/Forms/DialogForm.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.UI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Drawing; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | 12 | namespace Cupscale.Forms 13 | { 14 | public partial class DialogForm : Form 15 | { 16 | public DialogForm(string message, float selfDestructTime = 60f) 17 | { 18 | InitializeComponent(); 19 | Program.currentTemporaryForms.Add(this); 20 | mainLabel.Text = message; 21 | Show(); 22 | //TopMost = true; 23 | SelfDestruct(selfDestructTime); 24 | } 25 | 26 | public void ChangeText (string s) 27 | { 28 | mainLabel.Text = s; 29 | } 30 | 31 | public string GetText () 32 | { 33 | return mainLabel.Text; 34 | } 35 | 36 | private async Task SelfDestruct (float time) 37 | { 38 | await Task.Delay((time * 1000f).RoundToInt()); 39 | Close(); 40 | } 41 | 42 | private void DialogForm_FormClosing(object sender, FormClosingEventArgs e) 43 | { 44 | Program.currentTemporaryForms.Remove(this); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Code/Forms/InterpForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Cupscale.Forms 2 | { 3 | partial class AdvancedModelsForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.interpSlider = new System.Windows.Forms.TrackBar(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.panel1 = new System.Windows.Forms.Panel(); 34 | this.leftModelLabel = new System.Windows.Forms.Label(); 35 | this.panel2 = new System.Windows.Forms.Panel(); 36 | this.rightModelLabel = new System.Windows.Forms.Label(); 37 | this.saveBtn = new System.Windows.Forms.Button(); 38 | ((System.ComponentModel.ISupportInitialize)(this.interpSlider)).BeginInit(); 39 | this.panel1.SuspendLayout(); 40 | this.panel2.SuspendLayout(); 41 | this.SuspendLayout(); 42 | // 43 | // interpSlider 44 | // 45 | this.interpSlider.Location = new System.Drawing.Point(109, 185); 46 | this.interpSlider.Margin = new System.Windows.Forms.Padding(100, 10, 100, 10); 47 | this.interpSlider.Maximum = 20; 48 | this.interpSlider.Name = "interpSlider"; 49 | this.interpSlider.Size = new System.Drawing.Size(366, 45); 50 | this.interpSlider.TabIndex = 0; 51 | this.interpSlider.Value = 10; 52 | this.interpSlider.ValueChanged += new System.EventHandler(this.interpSlider_ValueChanged); 53 | // 54 | // label1 55 | // 56 | this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 57 | | System.Windows.Forms.AnchorStyles.Right))); 58 | this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 59 | this.label1.Location = new System.Drawing.Point(8, 9); 60 | this.label1.Name = "label1"; 61 | this.label1.Size = new System.Drawing.Size(560, 23); 62 | this.label1.TabIndex = 1; 63 | this.label1.Text = "Drag the slider to adjust how strong the effect of each model will be."; 64 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 65 | // 66 | // panel1 67 | // 68 | this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 69 | | System.Windows.Forms.AnchorStyles.Right))); 70 | this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 71 | this.panel1.Controls.Add(this.leftModelLabel); 72 | this.panel1.Location = new System.Drawing.Point(12, 72); 73 | this.panel1.Name = "panel1"; 74 | this.panel1.Size = new System.Drawing.Size(560, 40); 75 | this.panel1.TabIndex = 2; 76 | // 77 | // leftModelLabel 78 | // 79 | this.leftModelLabel.Dock = System.Windows.Forms.DockStyle.Fill; 80 | this.leftModelLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 81 | this.leftModelLabel.Location = new System.Drawing.Point(0, 0); 82 | this.leftModelLabel.Margin = new System.Windows.Forms.Padding(3); 83 | this.leftModelLabel.Name = "leftModelLabel"; 84 | this.leftModelLabel.Size = new System.Drawing.Size(558, 38); 85 | this.leftModelLabel.TabIndex = 0; 86 | this.leftModelLabel.Text = "Left Model Name: 50%"; 87 | this.leftModelLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 88 | // 89 | // panel2 90 | // 91 | this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 92 | | System.Windows.Forms.AnchorStyles.Right))); 93 | this.panel2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 94 | this.panel2.Controls.Add(this.rightModelLabel); 95 | this.panel2.Location = new System.Drawing.Point(12, 125); 96 | this.panel2.Margin = new System.Windows.Forms.Padding(3, 10, 3, 10); 97 | this.panel2.Name = "panel2"; 98 | this.panel2.Size = new System.Drawing.Size(560, 40); 99 | this.panel2.TabIndex = 3; 100 | // 101 | // rightModelLabel 102 | // 103 | this.rightModelLabel.Dock = System.Windows.Forms.DockStyle.Fill; 104 | this.rightModelLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 105 | this.rightModelLabel.Location = new System.Drawing.Point(0, 0); 106 | this.rightModelLabel.Name = "rightModelLabel"; 107 | this.rightModelLabel.Size = new System.Drawing.Size(558, 38); 108 | this.rightModelLabel.TabIndex = 0; 109 | this.rightModelLabel.Text = "Right Model Name: 50%"; 110 | this.rightModelLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 111 | // 112 | // saveBtn 113 | // 114 | this.saveBtn.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 115 | | System.Windows.Forms.AnchorStyles.Right))); 116 | this.saveBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); 117 | this.saveBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; 118 | this.saveBtn.Location = new System.Drawing.Point(159, 243); 119 | this.saveBtn.Margin = new System.Windows.Forms.Padding(150, 3, 150, 3); 120 | this.saveBtn.Name = "saveBtn"; 121 | this.saveBtn.Size = new System.Drawing.Size(266, 30); 122 | this.saveBtn.TabIndex = 8; 123 | this.saveBtn.Text = "Save"; 124 | this.saveBtn.UseVisualStyleBackColor = false; 125 | this.saveBtn.Click += new System.EventHandler(this.saveBtn_Click); 126 | // 127 | // AdvancedModelsForm 128 | // 129 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 130 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 131 | this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32))))); 132 | this.ClientSize = new System.Drawing.Size(584, 285); 133 | this.Controls.Add(this.saveBtn); 134 | this.Controls.Add(this.panel2); 135 | this.Controls.Add(this.panel1); 136 | this.Controls.Add(this.label1); 137 | this.Controls.Add(this.interpSlider); 138 | this.ForeColor = System.Drawing.Color.White; 139 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; 140 | this.Name = "AdvancedModelsForm"; 141 | this.Text = "Set Interpolation Factor"; 142 | this.Load += new System.EventHandler(this.InterpForm_Load); 143 | ((System.ComponentModel.ISupportInitialize)(this.interpSlider)).EndInit(); 144 | this.panel1.ResumeLayout(false); 145 | this.panel2.ResumeLayout(false); 146 | this.ResumeLayout(false); 147 | this.PerformLayout(); 148 | 149 | } 150 | 151 | #endregion 152 | 153 | private System.Windows.Forms.TrackBar interpSlider; 154 | private System.Windows.Forms.Label label1; 155 | private System.Windows.Forms.Panel panel1; 156 | private System.Windows.Forms.Label leftModelLabel; 157 | private System.Windows.Forms.Panel panel2; 158 | private System.Windows.Forms.Label rightModelLabel; 159 | private System.Windows.Forms.Button saveBtn; 160 | } 161 | } -------------------------------------------------------------------------------- /Code/Forms/InterpForm.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.UI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Drawing; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | 12 | namespace Cupscale.Forms 13 | { 14 | public partial class AdvancedModelsForm : Form 15 | { 16 | string leftModelName; 17 | string rightModelName; 18 | 19 | public AdvancedModelsForm(string leftModel, string rightModel) 20 | { 21 | leftModelName = leftModel; 22 | rightModelName = rightModel; 23 | InitializeComponent(); 24 | //Show(); 25 | CenterToParent(); 26 | } 27 | 28 | private void InterpForm_Load(object sender, EventArgs e) 29 | { 30 | interpSlider.Value = PreviewUi.interpValue / 5; 31 | UpdateLabels(); 32 | } 33 | 34 | private void saveBtn_Click(object sender, EventArgs e) 35 | { 36 | PreviewUi.interpValue = interpSlider.Value * 5; 37 | Close(); 38 | } 39 | 40 | private void interpSlider_ValueChanged(object sender, EventArgs e) 41 | { 42 | UpdateLabels(); 43 | } 44 | 45 | void UpdateLabels () 46 | { 47 | leftModelLabel.Text = leftModelName + ": " + (100 - interpSlider.Value * 5) + "%"; 48 | rightModelLabel.Text = rightModelName + ": " + interpSlider.Value * 5 + "%"; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Code/Forms/InterpForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Code/Forms/ModelComparisonForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Code/Forms/ModelSelectForm.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.IO; 2 | using Cupscale.OS; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Diagnostics; 8 | using System.Drawing; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | using System.Windows.Forms; 14 | 15 | namespace Cupscale.Forms 16 | { 17 | public partial class ModelSelectForm : Form 18 | { 19 | public string selectedModel { get; set; } 20 | public int modelNo; 21 | public Button modelBtn; 22 | 23 | public ModelSelectForm(Button modelButton, int modelNumber) 24 | { 25 | InitializeComponent(); 26 | modelBtn = modelButton; 27 | modelNo = modelNumber; 28 | SelectLastUsed(); 29 | } 30 | 31 | private void ModelSelectForm_Load(object sender, EventArgs e) 32 | { 33 | string modelDir = Config.Get("modelPath"); 34 | 35 | if (!Directory.Exists(modelDir)) 36 | { 37 | Program.ShowMessage("The saved model directory does not exist - Make sure you've set a models folder!"); 38 | Close(); 39 | return; 40 | } 41 | 42 | if (IoUtils.GetAmountOfFiles(modelDir, true, "*.pth") < 1) 43 | { 44 | Program.ShowMessage($"The saved model directory does not contain any model (.pth) files!\n\nPlease put some models into '{modelDir}'."); 45 | Close(); 46 | Process.Start("explorer.exe", Config.Get("modelPath")); 47 | return; 48 | } 49 | 50 | ForceLowercaseExtensions(modelDir); 51 | DirectoryInfo modelsDir = new DirectoryInfo(modelDir); 52 | BuildTree(modelsDir, modelTree.Nodes); 53 | 54 | if (Config.GetBool("modelSelectAutoExpand")) 55 | modelTree.ExpandAll(); 56 | else 57 | modelTree.Nodes[0].Expand(); 58 | } 59 | 60 | private async void SelectLastUsed() 61 | { 62 | if (!Directory.Exists(Config.Get("modelPath"))) 63 | return; 64 | 65 | while (modelTree.Nodes.Count < 1) 66 | await Task.Delay(100); 67 | 68 | if (string.IsNullOrWhiteSpace(Program.currentModel1)) 69 | modelTree.SelectedNode = modelTree.Nodes[0]; 70 | else 71 | CheckNodesRecursive(modelTree.Nodes[0]); 72 | } 73 | 74 | private void CheckNodesRecursive(TreeNode parentNode) 75 | { 76 | if (modelBtn != null && parentNode.Text.Trim() == modelBtn.Text.Trim()) 77 | modelTree.SelectedNode = parentNode; 78 | 79 | foreach (TreeNode subNode in parentNode.Nodes) 80 | { 81 | CheckNodesRecursive(subNode); 82 | } 83 | } 84 | 85 | private void ForceLowercaseExtensions(string path) 86 | { 87 | foreach (FileInfo file in IoUtils.GetFileInfosSorted(path, true, "*.*")) 88 | { 89 | if (file.Extension == ".PTH") 90 | file.MoveTo(Path.ChangeExtension(file.FullName, "pth")); 91 | } 92 | } 93 | 94 | private void BuildTree(DirectoryInfo directoryInfo, TreeNodeCollection nodeCollection) 95 | { 96 | TreeNode currNode = nodeCollection.Add(directoryInfo.Name); 97 | 98 | foreach (FileInfo file in directoryInfo.GetFiles()) 99 | { 100 | if (file.Extension == ".pth") // Hide any other file extension 101 | currNode.Nodes.Add(file.FullName, Path.ChangeExtension(file.Name, null)); 102 | } 103 | 104 | foreach (DirectoryInfo subDir in directoryInfo.GetDirectories()) 105 | { 106 | bool isNcnnModel = NcnnUtils.IsDirNcnnModel(subDir.FullName); 107 | 108 | if (isNcnnModel) 109 | currNode.Nodes.Add(subDir.FullName, subDir.Name.Substring(0, subDir.Name.Length - 5)); 110 | 111 | bool hasAnyPthFiles = subDir.GetFiles("*.pth", SearchOption.AllDirectories).Length > 0; 112 | bool hasAnyBinFiles = subDir.GetFiles("*.bin", SearchOption.AllDirectories).Length > 0; 113 | bool hasAnyParamFiles = subDir.GetFiles("*.param", SearchOption.AllDirectories).Length > 0; 114 | 115 | if (isNcnnModel || subDir.Name.StartsWith(".")) 116 | continue; // Don't add this folder to the tree if it's a model, not a dir with more models 117 | 118 | if (hasAnyPthFiles || hasAnyBinFiles || hasAnyParamFiles) // Don't list folders that have no model files 119 | BuildTree(subDir, currNode.Nodes); 120 | } 121 | } 122 | 123 | private void confirmBtn_Click(object sender, EventArgs e) 124 | { 125 | selectedModel = modelTree.SelectedNode.Name; 126 | string modelName = Path.GetFileNameWithoutExtension(selectedModel); 127 | 128 | if (modelBtn != null) 129 | modelBtn.Text = modelName; 130 | 131 | if (modelNo == 1) Program.currentModel1 = selectedModel; 132 | if (modelNo == 2) Program.currentModel2 = selectedModel; 133 | 134 | Config.Set("lastMdl1", Program.currentModel1); 135 | Config.Set("lastMdl2", Program.currentModel2); 136 | 137 | DialogResult = DialogResult.OK; 138 | Close(); 139 | } 140 | 141 | private void cancelBtn_Click(object sender, EventArgs e) 142 | { 143 | Close(); 144 | } 145 | 146 | private void modelTree_AfterSelect(object sender, TreeViewEventArgs e) 147 | { 148 | confirmBtn.Enabled = (Path.GetExtension(modelTree.SelectedNode.Name) == ".pth" || modelTree.SelectedNode.Name.EndsWith(".ncnn")); 149 | } 150 | 151 | private void ModelSelectForm_KeyPress(object sender, KeyPressEventArgs e) 152 | { 153 | if (e.KeyChar == (char)Keys.Enter) 154 | { 155 | e.Handled = true; 156 | if (confirmBtn.Enabled) 157 | confirmBtn_Click(null, null); 158 | } 159 | 160 | if (e.KeyChar == (char)Keys.Escape) 161 | { 162 | e.Handled = true; 163 | Close(); 164 | } 165 | } 166 | 167 | private void clearBtn_Click(object sender, EventArgs e) 168 | { 169 | selectedModel = ""; 170 | modelBtn.Text = "None"; 171 | if (modelNo == 1) Program.currentModel1 = null; 172 | if (modelNo == 2) Program.currentModel2 = null; 173 | DialogResult = DialogResult.OK; 174 | Close(); 175 | } 176 | 177 | private void openFolderBtn_Click(object sender, EventArgs e) 178 | { 179 | Process.Start("explorer.exe", Config.Get("modelPath")); 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /Code/Forms/ModelSelectForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Code/Forms/MsgBox.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Cupscale.Forms 2 | { 3 | partial class MsgBox 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.confirmBtn = new HTAlt.WinForms.HTButton(); 32 | this.msgTextbox = new System.Windows.Forms.TextBox(); 33 | this.SuspendLayout(); 34 | // 35 | // confirmBtn 36 | // 37 | this.confirmBtn.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 38 | | System.Windows.Forms.AnchorStyles.Right))); 39 | this.confirmBtn.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; 40 | this.confirmBtn.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); 41 | this.confirmBtn.FlatAppearance.BorderSize = 0; 42 | this.confirmBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; 43 | this.confirmBtn.ForeColor = System.Drawing.Color.White; 44 | this.confirmBtn.Location = new System.Drawing.Point(407, 177); 45 | this.confirmBtn.Margin = new System.Windows.Forms.Padding(8); 46 | this.confirmBtn.Name = "confirmBtn"; 47 | this.confirmBtn.Size = new System.Drawing.Size(200, 32); 48 | this.confirmBtn.TabIndex = 13; 49 | this.confirmBtn.Text = "OK"; 50 | this.confirmBtn.UseVisualStyleBackColor = false; 51 | this.confirmBtn.Click += new System.EventHandler(this.confirmBtn_Click); 52 | // 53 | // msgTextbox 54 | // 55 | this.msgTextbox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 56 | | System.Windows.Forms.AnchorStyles.Left) 57 | | System.Windows.Forms.AnchorStyles.Right))); 58 | this.msgTextbox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32))))); 59 | this.msgTextbox.BorderStyle = System.Windows.Forms.BorderStyle.None; 60 | this.msgTextbox.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 61 | this.msgTextbox.ForeColor = System.Drawing.Color.White; 62 | this.msgTextbox.Location = new System.Drawing.Point(28, 17); 63 | this.msgTextbox.Margin = new System.Windows.Forms.Padding(8); 64 | this.msgTextbox.Multiline = true; 65 | this.msgTextbox.Name = "msgTextbox"; 66 | this.msgTextbox.ReadOnly = true; 67 | this.msgTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; 68 | this.msgTextbox.Size = new System.Drawing.Size(579, 144); 69 | this.msgTextbox.TabIndex = 35; 70 | this.msgTextbox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; 71 | this.msgTextbox.TextChanged += new System.EventHandler(this.msgTextbox_TextChanged); 72 | // 73 | // MsgBox 74 | // 75 | this.AcceptButton = this.confirmBtn; 76 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 77 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 78 | this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(32)))), ((int)(((byte)(32))))); 79 | this.ClientSize = new System.Drawing.Size(624, 226); 80 | this.Controls.Add(this.msgTextbox); 81 | this.Controls.Add(this.confirmBtn); 82 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; 83 | this.MaximizeBox = false; 84 | this.MinimizeBox = false; 85 | this.Name = "MsgBox"; 86 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 87 | this.Text = "Message"; 88 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MsgBox_FormClosing); 89 | this.Load += new System.EventHandler(this.MsgBox_Load); 90 | this.ResumeLayout(false); 91 | this.PerformLayout(); 92 | 93 | } 94 | 95 | #endregion 96 | 97 | private HTAlt.WinForms.HTButton confirmBtn; 98 | private System.Windows.Forms.TextBox msgTextbox; 99 | } 100 | } -------------------------------------------------------------------------------- /Code/Forms/MsgBox.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.UI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Drawing; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Text.RegularExpressions; 10 | using System.Threading.Tasks; 11 | using System.Windows.Forms; 12 | 13 | namespace Cupscale.Forms 14 | { 15 | public partial class MsgBox : Form 16 | { 17 | public bool usedConfirmBtn; 18 | 19 | public MsgBox(string msg, string title = "Message") 20 | { 21 | InitializeComponent(); 22 | Text = title; 23 | msgTextbox.Text = msg; 24 | } 25 | 26 | private void MsgBox_Load(object sender, EventArgs e) 27 | { 28 | 29 | } 30 | 31 | private void confirmBtn_Click(object sender, EventArgs e) 32 | { 33 | usedConfirmBtn = true; 34 | DialogResult = DialogResult.OK; 35 | DialogQueue.CloseCurrent(); 36 | } 37 | 38 | private void msgTextbox_TextChanged(object sender, EventArgs e) 39 | { 40 | int linebreaks = Regex.Split(msgTextbox.Text, "\r\n|\r|\n").Length; 41 | if (linebreaks > 6) 42 | msgTextbox.ScrollBars = ScrollBars.Vertical; 43 | else 44 | msgTextbox.ScrollBars = ScrollBars.None; 45 | 46 | if (linebreaks > 10) 47 | Size = new Size(Size.Width, 450); 48 | 49 | if (msgTextbox.Text.Contains("Stack Trace")) 50 | msgTextbox.TextAlign = HorizontalAlignment.Left; 51 | else 52 | msgTextbox.TextAlign = HorizontalAlignment.Center; 53 | } 54 | 55 | private void MsgBox_FormClosing(object sender, FormClosingEventArgs e) 56 | { 57 | if (!usedConfirmBtn) 58 | { 59 | DialogResult = DialogResult.OK; 60 | DialogQueue.CloseCurrent(); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Code/Forms/MsgBox.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Code/IO/ConfigParser.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.UI; 2 | using System; 3 | using System.Windows.Forms; 4 | 5 | namespace Cupscale.IO 6 | { 7 | class ConfigParser 8 | { 9 | 10 | public enum StringMode { Any, Int, Float } 11 | 12 | public static void SaveGuiElement(TextBox textbox, StringMode stringMode = StringMode.Any) 13 | { 14 | switch (stringMode) 15 | { 16 | case StringMode.Any: Config.Set(textbox.Name, textbox.Text); break; 17 | case StringMode.Int: Config.Set(textbox.Name, textbox.Text.GetInt().ToString()); break; 18 | case StringMode.Float: Config.Set(textbox.Name, textbox.Text.GetFloat().ToString()); break; 19 | } 20 | } 21 | 22 | public static void SaveGuiElement(ComboBox comboBox, StringMode stringMode = StringMode.Any) 23 | { 24 | switch (stringMode) 25 | { 26 | case StringMode.Any: Config.Set(comboBox.Name, comboBox.Text); break; 27 | case StringMode.Int: Config.Set(comboBox.Name, comboBox.Text.GetInt().ToString()); break; 28 | case StringMode.Float: Config.Set(comboBox.Name, comboBox.Text.GetFloat().ToString().Replace(",", ".")); break; 29 | } 30 | } 31 | 32 | public static void SaveGuiElement(CheckBox checkbox) 33 | { 34 | Config.Set(checkbox.Name, checkbox.Checked.ToString()); 35 | } 36 | 37 | public static void SaveGuiElement(NumericUpDown upDown, StringMode stringMode = StringMode.Any) 38 | { 39 | switch (stringMode) 40 | { 41 | case StringMode.Any: Config.Set(upDown.Name, ((float)upDown.Value).ToString().Replace(",", ".")); break; 42 | case StringMode.Int: Config.Set(upDown.Name, ((int)upDown.Value).ToString()); break; 43 | case StringMode.Float: Config.Set(upDown.Name, ((float)upDown.Value).ToString().Replace(",", ".")); ; break; 44 | } 45 | } 46 | 47 | public static void SaveComboxIndex(ComboBox comboBox) 48 | { 49 | Config.Set(comboBox.Name, comboBox.SelectedIndex.ToString()); 50 | } 51 | 52 | public static void LoadGuiElement(ComboBox comboBox, string suffix = "") 53 | { 54 | comboBox.Text = Config.Get(comboBox.Name) + suffix; 55 | } 56 | 57 | public static void LoadGuiElement(TextBox textbox, string suffix = "") 58 | { 59 | textbox.Text = Config.Get(textbox.Name) + suffix; ; 60 | } 61 | 62 | public static void LoadGuiElement(CheckBox checkbox) 63 | { 64 | checkbox.Checked = Config.GetBool(checkbox.Name); 65 | } 66 | 67 | public static void LoadGuiElement(NumericUpDown upDown) 68 | { 69 | upDown.Value = Convert.ToDecimal(Config.GetFloat(upDown.Name)); 70 | } 71 | 72 | public static void LoadComboxIndex(ComboBox comboBox) 73 | { 74 | comboBox.SelectedIndex = Config.GetInt(comboBox.Name); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Code/IO/Installer.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/IO/Installer.cs -------------------------------------------------------------------------------- /Code/IO/Paths.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cupscale.UI; 3 | using System.IO; 4 | 5 | namespace Cupscale.IO 6 | { 7 | internal class Paths 8 | { 9 | 10 | public static string binPath; 11 | public static string defaultModelPath; 12 | public static string previewPath; 13 | public static string previewOutPath; 14 | public static string imgInPath; 15 | public static string imgOutPath; 16 | public static string tempImgPath; 17 | public static string clipboardFolderPath; 18 | public static string presetsPath; 19 | public static string compositionOut; 20 | public static string framesOutPath; 21 | 22 | public static readonly string pythonTuringPath = "flowframes/setupfiles/py-tu/v1/py-tu.7z"; 23 | public static readonly string pythonAmperePath = "flowframes/setupfiles/py-amp/v1/py-amp.7z"; 24 | 25 | public static readonly string ncnnMdlDir = ".ncnn-models"; 26 | 27 | public static void Init() 28 | { 29 | binPath = Path.Combine(GetDataPath(), "bin"); 30 | 31 | defaultModelPath = Path.Combine(GetDataPath(), "models"); 32 | Directory.CreateDirectory(defaultModelPath); 33 | 34 | previewPath = Path.Combine(GetDataPath(), "preview"); 35 | Directory.CreateDirectory(previewPath); 36 | 37 | previewOutPath = Path.Combine(GetDataPath(), "preview-out"); 38 | Directory.CreateDirectory(previewOutPath); 39 | 40 | imgInPath = Path.Combine(GetDataPath(), "img-in"); 41 | Directory.CreateDirectory(imgInPath); 42 | 43 | imgOutPath = Path.Combine(GetDataPath(), "img-out"); 44 | Directory.CreateDirectory(imgOutPath); 45 | 46 | tempImgPath = Path.Combine(GetDataPath(), "loaded-img", "temp.png"); 47 | Directory.CreateDirectory(tempImgPath.GetParentDir()); 48 | 49 | clipboardFolderPath = Path.Combine(GetDataPath(), "clipboard"); 50 | Directory.CreateDirectory(clipboardFolderPath); 51 | 52 | presetsPath = Path.Combine(GetDataPath(), "model-presets"); 53 | Directory.CreateDirectory(presetsPath); 54 | 55 | compositionOut = Path.Combine(GetDataPath(), "composition"); 56 | Directory.CreateDirectory(compositionOut); 57 | 58 | framesOutPath = Path.Combine(GetDataPath(), "frames-out"); 59 | Directory.CreateDirectory(framesOutPath); 60 | } 61 | 62 | public static string GetDataPath() 63 | { 64 | string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 65 | path = Path.Combine(path, "Cupscale"); 66 | 67 | if (IoUtils.IsPortable()) 68 | { 69 | if (!IoUtils.hasShownPortableInfo) 70 | { 71 | Logger.Log("Running in portable mode. Data folder: " + Path.Combine(GetExeDir(), "CupscaleData"), false); 72 | IoUtils.hasShownPortableInfo = true; 73 | } 74 | path = Path.Combine(GetExeDir(), "CupscaleData"); 75 | } 76 | 77 | Directory.CreateDirectory(path); 78 | return path; 79 | } 80 | 81 | public static string GetExeDir() 82 | { 83 | return AppDomain.CurrentDomain.BaseDirectory; 84 | } 85 | 86 | public static string GetAiDir (Implementations.Implementation impl) 87 | { 88 | return Path.Combine(binPath, impl.dir); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Code/ImageUtils/Filters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Cupscale.ImageUtils 8 | { 9 | class Filters 10 | { 11 | public static Filter mitchell = new Filter { Name = "Mitchell", Alias = "Mitchell" }; 12 | public static Filter bicubic = new Filter { Name = "Catrom", Alias = "Bicubic" }; 13 | public static Filter nearest = new Filter { Name = "Point", Alias = "Nearest Neighbor" }; 14 | public static Filter lanczos = new Filter { Name = "Lanczos", Alias = "Lanczos" }; 15 | //public static Filter lanczos2 = new Filter { Name = "Lanczos2", Alias = "Lanczos 2" }; 16 | //public static Filter lanczos2Sharp = new Filter { Name = "Lanczos2Sharp", Alias = "Lanczos 2 Sharp" }; 17 | 18 | public static List allFilters = new List { mitchell, bicubic, nearest, lanczos }; 19 | public static List previewFilters = new List { bicubic, nearest }; 20 | public static List resizeFilters = new List { mitchell, bicubic, nearest, lanczos }; 21 | 22 | public class Filter 23 | { 24 | public string Name = ""; 25 | public string Alias = ""; 26 | } 27 | 28 | public static Filter GetFilter(string alias) 29 | { 30 | foreach(Filter f in allFilters) 31 | { 32 | if (f.Alias == alias) 33 | return f; 34 | } 35 | 36 | return mitchell; 37 | } 38 | 39 | public static ImageMagick.FilterType GetMagickFilter(string alias) 40 | { 41 | return (ImageMagick.FilterType)Enum.Parse(typeof(ImageMagick.FilterType), GetFilter(alias).Name); 42 | } 43 | 44 | public static ImageMagick.FilterType GetMagickFilter(Filter filter) 45 | { 46 | return (ImageMagick.FilterType)Enum.Parse(typeof(ImageMagick.FilterType), filter.Name); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Code/ImageUtils/ImageOperations.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Cupscale.ImageUtils 10 | { 11 | class ImageOperations 12 | { 13 | public static Image Scale (Image img, float scale = 1f, InterpolationMode filtering = InterpolationMode.NearestNeighbor) 14 | { 15 | var destImage = new Bitmap((int)Math.Round(img.Width * scale), (int)Math.Round(img.Height * scale)); 16 | 17 | using (var graphics = Graphics.FromImage(destImage)) 18 | { 19 | graphics.CompositingMode = CompositingMode.SourceCopy; 20 | graphics.CompositingQuality = CompositingQuality.HighQuality; 21 | graphics.InterpolationMode = filtering; 22 | graphics.SmoothingMode = SmoothingMode.HighQuality; 23 | graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; 24 | 25 | graphics.DrawImage(img, 0, 0, destImage.Width, destImage.Height); // Scale up 26 | } 27 | 28 | return destImage; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Code/ImageUtils/ImgUtils.cs: -------------------------------------------------------------------------------- 1 | using DdsFileTypePlus; 2 | using ImageMagick; 3 | using Microsoft.WindowsAPICodePack.Shell; 4 | using PaintDotNet; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.Drawing; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | using System.Windows.Forms; 14 | using System.Windows.Media.Imaging; 15 | 16 | namespace Cupscale.ImageUtils 17 | { 18 | class ImgUtils 19 | { 20 | public static Image GetImage(string path) 21 | { 22 | if (Logger.doLogIo) Logger.Log("[ImgUtils] Reading Image from " + path); 23 | using MemoryStream stream = new MemoryStream(File.ReadAllBytes(path)); 24 | Image img = Image.FromStream(stream); 25 | if (Logger.doLogIo) Logger.Log("[OK]", true, true); 26 | return img; 27 | } 28 | 29 | public static MagickImage GetMagickImage(string path, bool allowTgaFlip = false) 30 | { 31 | if (Logger.doLogIo) Logger.Log("[ImgUtils] Reading MagickImage from " + path); 32 | MagickImage image; 33 | if (Path.GetExtension(path).ToLower() == ".dds") 34 | { 35 | try 36 | { 37 | image = new MagickImage(path); // Try reading DDS with IM, fall back to DdsFileTypePlusHack if it fails 38 | } 39 | catch (Exception magickEx) 40 | { 41 | Logger.Log($"[ImgUtils] Failed to read DDS using Magick.NET ({magickEx.Message}) - Trying DdsFileTypePlusHack"); 42 | try 43 | { 44 | Surface surface = DdsFile.Load(path); 45 | image = ConvertToMagickImage(surface); 46 | image.HasAlpha = DdsFile.HasTransparency(surface); 47 | } 48 | catch (Exception ddsEx) 49 | { 50 | Logger.ErrorMessage("[ImgUtils] This DDS format appears to be incompatible.", ddsEx); 51 | return null; 52 | } 53 | } 54 | } 55 | else 56 | { 57 | image = new MagickImage(path); 58 | } 59 | if (allowTgaFlip && Path.GetExtension(path).ToLower() == ".tga" && Config.GetBool("flipTga")) 60 | { 61 | image.Flip(); 62 | if (Logger.doLogIo) Logger.Log("[Flipped TGA]", true, true); 63 | } 64 | if (Logger.doLogIo) Logger.Log("[OK]", true, true); 65 | return image; 66 | } 67 | 68 | public static MagickImage ConvertToMagickImage(Surface surface) 69 | { 70 | MagickImage result; 71 | Bitmap bitmap = surface.CreateAliasedBitmap(); 72 | using (MemoryStream memoryStream = new MemoryStream()) 73 | { 74 | bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png); 75 | memoryStream.Position = 0; 76 | result = new MagickImage(memoryStream, new MagickReadSettings() { Format = MagickFormat.Png00 }); 77 | } 78 | return result; 79 | } 80 | 81 | public static float GetScale(Image imgFrom, Image imgTo) 82 | { 83 | return (int)Math.Round(GetScaleFloat(imgFrom, imgTo)); 84 | } 85 | 86 | public static float GetScaleFloat(Image imgFrom, Image imgTo) 87 | { 88 | return (float)imgTo.Width / (float)imgFrom.Width; 89 | } 90 | 91 | public static MagickImage FillAlphaWithBgColor(MagickImage img) 92 | { 93 | return FillAlphaWithColor(img, new MagickColor("#" + Config.Get("alphaBgColor"))); 94 | } 95 | 96 | public static MagickImage FillAlphaWithColor(MagickImage img, MagickColor color) 97 | { 98 | MagickImage bg = new MagickImage(color, img.Width, img.Height); 99 | bg.BackgroundColor = color; 100 | bg.Composite(img, CompositeOperator.Over); 101 | 102 | return bg; 103 | } 104 | 105 | public static int GetColorDepth(string path) 106 | { 107 | try 108 | { 109 | ShellFile shellFile = ShellFile.FromFilePath(path); 110 | int depth = (int)shellFile.Properties.System.Image.BitDepth.Value; 111 | return depth; 112 | //MemoryStream stream = new MemoryStream(File.ReadAllBytes(path)); 113 | //var source = BitmapFrame.Create(stream, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnDemand); 114 | //return source.Format.BitsPerPixel; 115 | } 116 | catch (Exception e) 117 | { 118 | Logger.Log("[ImgUtils] Failed to read color depth: " + e.Message + " - Defaulting to 32."); 119 | return 32; 120 | } 121 | } 122 | 123 | public static MagickImage MergeImages(string[] imgs, bool vertically, bool deleteSourceImgs) 124 | { 125 | MagickImageCollection collection = new MagickImageCollection(); 126 | 127 | foreach (string img in imgs) 128 | { 129 | collection.Add(img); 130 | if (deleteSourceImgs) 131 | File.Delete(img); 132 | } 133 | 134 | if (!vertically) 135 | return (MagickImage)collection.AppendHorizontally(); 136 | else 137 | return (MagickImage)collection.AppendVertically(); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Code/ImageUtils/MozJpeg.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using MozJpegSharp; 6 | 7 | namespace Cupscale.ImageUtils 8 | { 9 | class MozJpeg 10 | { 11 | public static void Encode(string inPath, string outPath, int q, bool chromaSubSample = true) 12 | { 13 | try 14 | { 15 | Bitmap bmp = (Bitmap)ImgUtils.GetImage(inPath); 16 | var commpressor = new TJCompressor(); 17 | byte[] compressed; 18 | TJSubsamplingOption subSample = TJSubsamplingOption.Chrominance420; 19 | if (!chromaSubSample) 20 | subSample = TJSubsamplingOption.Chrominance444; 21 | compressed = commpressor.Compress(bmp, subSample, q, TJFlags.None); 22 | File.WriteAllBytes(outPath, compressed); 23 | Logger.Log("[MozJpeg] Written image to " + outPath); 24 | } 25 | catch (TypeInitializationException e) 26 | { 27 | Logger.ErrorMessage($"MozJpeg Initialization Error: {e.InnerException.Message}\n", e); 28 | } 29 | catch (Exception e) 30 | { 31 | Logger.ErrorMessage("MozJpeg Error: ", e); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Code/ImageUtils/NvCompress.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.IO; 2 | using Cupscale.UI; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Cupscale.ImageUtils 12 | { 13 | class NvCompress 14 | { 15 | static Process currentProcess; 16 | 17 | public static async Task PngToDds (string inputFile, string outputPath) 18 | { 19 | string dxtString = Config.Get("dxtMode").ToLower().Replace("argb", "rgb"); 20 | if (dxtString.Contains(" ")) 21 | dxtString = dxtString.Split(' ')[0]; 22 | await Run(inputFile, outputPath, dxtString, Config.GetBool("alpha"), Config.GetBool("ddsEnableMips")); 23 | 24 | } 25 | 26 | public static async Task Run(string inpath, string outpath, string dxtMode, bool alpha, bool enableMips) 27 | { 28 | bool showWindow = Config.GetInt("cmdDebugMode") > 0; 29 | bool stayOpen = Config.GetInt("cmdDebugMode") == 2; 30 | 31 | if (Path.GetExtension(inpath).ToLower() != ".png") 32 | { 33 | string newPath = Path.ChangeExtension(inpath, "png"); 34 | File.Move(inpath, newPath); 35 | inpath = newPath; 36 | } 37 | 38 | string alphaStr = ""; 39 | if (alpha) 40 | alphaStr = "-alpha"; 41 | 42 | string mipStr = "-nomips"; 43 | if (enableMips) 44 | mipStr = ""; 45 | 46 | string opt = "/C"; 47 | if (stayOpen) opt = "/K"; 48 | 49 | string args = $"{opt} cd /D {Paths.binPath.Wrap()} & "; 50 | args += $"nvcompress.exe -{dxtMode} {alphaStr} {mipStr} {inpath.Wrap()} {outpath.Wrap()}"; 51 | Logger.Log("[CMD] " + args); 52 | Process nvCompress = new Process(); 53 | nvCompress.StartInfo.UseShellExecute = showWindow; 54 | nvCompress.StartInfo.RedirectStandardOutput = !showWindow; 55 | nvCompress.StartInfo.RedirectStandardError = !showWindow; 56 | nvCompress.StartInfo.CreateNoWindow = !showWindow; 57 | nvCompress.StartInfo.FileName = "cmd.exe"; 58 | nvCompress.StartInfo.Arguments = args; 59 | if (!showWindow) 60 | { 61 | nvCompress.OutputDataReceived += OutputHandler; 62 | nvCompress.ErrorDataReceived += OutputHandler; 63 | } 64 | currentProcess = nvCompress; 65 | nvCompress.Start(); 66 | if (!showWindow) 67 | { 68 | nvCompress.BeginOutputReadLine(); 69 | nvCompress.BeginErrorReadLine(); 70 | } 71 | 72 | while (!nvCompress.HasExited) 73 | await Task.Delay(50); 74 | 75 | if (inpath.ToLower() != outpath.ToLower()) 76 | File.Delete(inpath); 77 | } 78 | 79 | private static void OutputHandler(object sendingProcess, DataReceivedEventArgs output) 80 | { 81 | if (output == null || output.Data == null) 82 | return; 83 | 84 | string data = output.Data; 85 | 86 | if(data.Length >= 4) 87 | Logger.Log("[NvCompress] " + data.Replace("\n", " ").Replace("\r", " ")); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Code/Implementations/EsrganNcnn.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.Cupscale; 2 | using Cupscale.IO; 3 | using Cupscale.Main; 4 | using Upscale = Cupscale.Main.Upscale; 5 | using Cupscale.UI; 6 | using System; 7 | using System.Diagnostics; 8 | using System.Drawing; 9 | using System.IO; 10 | using System.Threading.Tasks; 11 | using Paths = Cupscale.IO.Paths; 12 | using Cupscale.Implementations; 13 | using Cupscale.OS; 14 | using Cupscale.Data; 15 | 16 | namespace Cupscale.Implementations 17 | { 18 | class EsrganNcnn : ImplementationBase 19 | { 20 | static readonly string exeName = "esrgan-ncnn-vulkan.exe"; 21 | 22 | public static async Task Run(string inpath, string outpath, ModelData mdl) 23 | { 24 | if (!CheckIfExeExists(Imps.esrganNcnn, exeName)) 25 | return; 26 | 27 | string modelPath = mdl.model1Path; 28 | Program.lastModelName = mdl.model1Name; 29 | 30 | bool showWindow = Config.GetInt("cmdDebugMode") > 0; 31 | bool stayOpen = Config.GetInt("cmdDebugMode") == 2; 32 | 33 | Program.mainForm.SetProgress(1f, "Converting model..."); 34 | await NcnnUtils.ConvertNcnnModel(modelPath, "x*"); 35 | Logger.Log("[ESRGAN] NCNN Model is ready: " + NcnnUtils.currentNcnnModel); 36 | Program.mainForm.SetProgress(3f, "Loading ESRGAN (NCNN)..."); 37 | int scale = NcnnUtils.GetNcnnModelScale(NcnnUtils.currentNcnnModel); 38 | string opt = stayOpen ? "/K" : "/C"; 39 | string tta = Config.GetBool("esrganNcnnTta") ? "-x" : ""; 40 | string ts = Config.GetInt("esrganNcnnTilesize") >= 32 ? $"-t {Config.GetInt("esrganNcnnTilesize")}" : ""; 41 | string cmd = $"{opt} cd /D {Path.Combine(Paths.binPath, Imps.esrganNcnn.dir).Wrap()} & {exeName} -i {inpath.Wrap()} -o {outpath.Wrap()}" + 42 | $" -g {Config.GetInt("esrganNcnnGpu")} -m {NcnnUtils.currentNcnnModel.Wrap()} -s {scale} {tta} {ts}"; 43 | Logger.Log("[CMD] " + cmd); 44 | 45 | Process proc = OsUtils.NewProcess(!showWindow); 46 | proc.StartInfo.Arguments = cmd; 47 | 48 | if (!showWindow) 49 | { 50 | proc.OutputDataReceived += (sender, outLine) => { OutputHandler(outLine.Data, false); }; 51 | proc.ErrorDataReceived += (sender, outLine) => { OutputHandler(outLine.Data, true); }; 52 | } 53 | 54 | Program.lastImpProcess = proc; 55 | proc.Start(); 56 | 57 | if (!showWindow) 58 | { 59 | proc.BeginOutputReadLine(); 60 | proc.BeginErrorReadLine(); 61 | } 62 | 63 | while (!proc.HasExited) 64 | await Task.Delay(50); 65 | 66 | if (Upscale.currentMode == Upscale.UpscaleMode.Batch) 67 | { 68 | await Task.Delay(1000); 69 | Program.mainForm.SetProgress(100f, "Post-Processing..."); 70 | PostProcessingQueue.Stop(); 71 | } 72 | } 73 | 74 | private static void OutputHandler(string line, bool error) 75 | { 76 | if (string.IsNullOrWhiteSpace(line) || line.Length < 6) 77 | return; 78 | 79 | Logger.Log("[NCNN] " + line.Replace("\n", " ").Replace("\r", " ")); 80 | 81 | if(error) 82 | GeneralOutputHandler.HandleImpErrorMsgs(line, GeneralOutputHandler.ProcessType.Ncnn); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Code/Implementations/Implementation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Cupscale.Implementations 8 | { 9 | public class Implementation 10 | { 11 | public string name = ""; 12 | public string dir = ""; 13 | public bool supportsModels = true; 14 | public bool supportsInterp = true; 15 | public bool supportsChain = true; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Code/Implementations/ImplementationBase.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.IO; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Cupscale.Implementations 10 | { 11 | public abstract class ImplementationBase 12 | { 13 | public static bool CheckIfExeExists (Implementation implementation, string exeName) 14 | { 15 | if (!File.Exists(Path.Combine(Paths.binPath, implementation.dir, exeName))) 16 | { 17 | Program.ShowMessage($"Error: The executable is missing:\n\n{exeName}\n\nPossibly your installation is incomplete?", "Error"); 18 | return false; 19 | } 20 | 21 | return true; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Code/Implementations/Imps.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Cupscale.Implementations 8 | { 9 | class Imps 10 | { 11 | public static List impList = new List(); 12 | 13 | public static Implementation esrganPytorch = new Implementation 14 | { name="ESRGAN (Pytorch)", dir = "esrgan-pytorch", supportsInterp = true, supportsChain = true }; 15 | 16 | public static Implementation esrganNcnn = new Implementation 17 | { name = "ESRGAN (NCNN)", dir = "esrgan-ncnn", supportsInterp = false, supportsChain = false }; 18 | 19 | public static Implementation realEsrganNcnn = new Implementation 20 | { name = "RealESRGAN (NCNN)", dir = "realesrgan-ncnn", supportsInterp = false, supportsChain = false }; 21 | 22 | public static void Init() 23 | { 24 | impList.Clear(); 25 | impList.Add(esrganPytorch); 26 | impList.Add(esrganNcnn); 27 | impList.Add(realEsrganNcnn); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Code/Implementations/RealEsrganNcnn.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.Cupscale; 2 | using Cupscale.IO; 3 | using Cupscale.Main; 4 | using Upscale = Cupscale.Main.Upscale; 5 | using Cupscale.UI; 6 | using System; 7 | using System.Diagnostics; 8 | using System.IO; 9 | using System.Linq.Expressions; 10 | using System.Threading.Tasks; 11 | using Paths = Cupscale.IO.Paths; 12 | using Cupscale.Implementations; 13 | using Cupscale.OS; 14 | using Cupscale.Data; 15 | 16 | namespace Cupscale.Implementations 17 | { 18 | class RealEsrganNcnn : ImplementationBase 19 | { 20 | static readonly string exeName = "realesrgan-ncnn-vulkan.exe"; 21 | 22 | public static async Task Run(string inpath, string outpath, ModelData mdl) 23 | { 24 | if (!CheckIfExeExists(Imps.realEsrganNcnn, exeName)) 25 | return; 26 | 27 | string modelPath = mdl.model1Path; 28 | Program.lastModelName = mdl.model1Name; 29 | 30 | bool showWindow = Config.GetInt("cmdDebugMode") > 0; 31 | bool stayOpen = Config.GetInt("cmdDebugMode") == 2; 32 | 33 | Program.mainForm.SetProgress(1f, "Converting model..."); 34 | await NcnnUtils.ConvertNcnnModel(modelPath, "esrgan-x*"); 35 | Logger.Log("[ESRGAN] NCNN Model is ready: " + NcnnUtils.currentNcnnModel); 36 | Program.mainForm.SetProgress(3f, "Loading RealESRGAN (NCNN)..."); 37 | int scale = NcnnUtils.GetNcnnModelScale(NcnnUtils.currentNcnnModel); 38 | 39 | if(scale != 4) 40 | { 41 | Program.ShowMessage($"Error: This implementation currently only supports 4x scale models.", "Error"); 42 | return; 43 | } 44 | 45 | string opt = stayOpen ? "/K" : "/C"; 46 | string tta = Config.GetBool("realEsrganNcnnTta") ? "-x" : ""; 47 | string ts = Config.GetInt("realEsrganNcnnTilesize") >= 32 ? $"-t {Config.GetInt("realEsrganNcnnTilesize")}" : ""; 48 | string cmd = $"{opt} cd /D {Path.Combine(Paths.binPath, Imps.realEsrganNcnn.dir).Wrap()} & {exeName} -i {inpath.Wrap()} -o {outpath.Wrap()}" + 49 | $" -g {Config.GetInt("realEsrganNcnnGpus")} -m {NcnnUtils.currentNcnnModel.Wrap()} -n esrgan-x4 -s {scale} {tta} {ts}"; 50 | Logger.Log("[CMD] " + cmd); 51 | 52 | Process proc = OsUtils.NewProcess(!showWindow); 53 | proc.StartInfo.Arguments = cmd; 54 | 55 | if (!showWindow) 56 | { 57 | proc.OutputDataReceived += (sender, outLine) => { OutputHandler(outLine.Data, false); }; 58 | proc.ErrorDataReceived += (sender, outLine) => { OutputHandler(outLine.Data, true); }; 59 | } 60 | 61 | Program.lastImpProcess = proc; 62 | proc.Start(); 63 | 64 | if (!showWindow) 65 | { 66 | proc.BeginOutputReadLine(); 67 | proc.BeginErrorReadLine(); 68 | } 69 | 70 | while (!proc.HasExited) 71 | await Task.Delay(50); 72 | 73 | if (Upscale.currentMode == Upscale.UpscaleMode.Batch) 74 | { 75 | await Task.Delay(1000); 76 | Program.mainForm.SetProgress(100f, "Post-Processing..."); 77 | PostProcessingQueue.Stop(); 78 | } 79 | 80 | } 81 | 82 | private static void OutputHandler(string line, bool error) 83 | { 84 | if (string.IsNullOrWhiteSpace(line) || line.Length < 6) 85 | return; 86 | 87 | Logger.Log("[NCNN] " + line.Replace("\n", " ").Replace("\r", " ")); 88 | 89 | bool showTileProgress = Upscale.currentMode == Upscale.UpscaleMode.Preview || Upscale.currentMode == Upscale.UpscaleMode.Single; 90 | 91 | if (showTileProgress && line.Trim().EndsWith("%")) 92 | { 93 | float percent = float.Parse(line.Replace("%", "").Replace(",", ".")) / 100f; 94 | Program.mainForm.SetProgress(percent, $"Upscaling Tiles ({percent}%)"); 95 | } 96 | 97 | if (error) 98 | GeneralOutputHandler.HandleImpErrorMsgs(line, GeneralOutputHandler.ProcessType.Ncnn); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Code/Main/AdvancedModelSelection.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.IO; 2 | using Cupscale.UI; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics.Contracts; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Cupscale.Main 12 | { 13 | class AdvancedModelSelection 14 | { 15 | // Models 16 | public static string e1m1; 17 | public static string e1m2; 18 | 19 | public static string e2m1; 20 | public static string e2m2; 21 | 22 | public static string e3m1; 23 | public static string e3m2; 24 | 25 | // Interp values 26 | public static int e1m1i; 27 | public static int e1m2i; 28 | 29 | public static int e2m1i; 30 | public static int e2m2i; 31 | 32 | public static int e3m1i; 33 | public static int e3m2i; 34 | 35 | public static void SavePreset (string name) 36 | { 37 | string saveData = $"name|{name}" + Environment.NewLine 38 | + $"e1m1|{e1m1}" + Environment.NewLine 39 | + $"e1m1i|{e1m1i}" + Environment.NewLine 40 | + $"e1m2|{e1m2}" + Environment.NewLine 41 | + $"e1m2i|{e1m2i}" + Environment.NewLine 42 | + $"e2m1|{e2m1}" + Environment.NewLine 43 | + $"e2m1i|{e2m1i}" + Environment.NewLine 44 | + $"e2m2|{e2m2}" + Environment.NewLine 45 | + $"e2m2i|{e2m2i}" + Environment.NewLine 46 | + $"e3m1|{e3m1}" + Environment.NewLine 47 | + $"e3m1i|{e3m1i}" + Environment.NewLine 48 | + $"e3m2|{e3m2}" + Environment.NewLine 49 | + $"e3m2i|{e3m2i}"; 50 | 51 | string path = Path.Combine(Paths.presetsPath, name); 52 | File.WriteAllText(path, saveData); 53 | Logger.Log("Saved model preset to " + path); 54 | } 55 | 56 | public static bool LoadPreset(string name) 57 | { 58 | string path = Path.Combine(Paths.presetsPath, name); 59 | if (!File.Exists(path)) 60 | return false; 61 | 62 | string[] saveDataLines = IoUtils.ReadLines(path); 63 | foreach(string line in saveDataLines) 64 | { 65 | string[] keyValuePair = line.Split('|'); 66 | switch (keyValuePair[0]) 67 | { 68 | case "e1m1": e1m1 = keyValuePair[1]; break; 69 | case "e1m1i": e1m1i = keyValuePair[1].GetInt(); break; 70 | case "e1m2": e1m2 = keyValuePair[1]; break; 71 | case "e1m2i": e1m2i = keyValuePair[1].GetInt(); break; 72 | 73 | case "e2m1": e2m1 = keyValuePair[1]; break; 74 | case "e2m1i": e2m1i = keyValuePair[1].GetInt(); break; 75 | case "e2m2": e2m2 = keyValuePair[1]; break; 76 | case "e2m2i": e2m2i = keyValuePair[1].GetInt(); break; 77 | 78 | case "e3m1": e3m1 = keyValuePair[1]; break; 79 | case "e3m1i": e3m1i = keyValuePair[1].GetInt(); break; 80 | case "e3m2": e3m2 = keyValuePair[1]; break; 81 | case "e3m2i": e3m2i = keyValuePair[1].GetInt(); break; 82 | } 83 | } 84 | 85 | Logger.Log("Loaded model preset " + name); 86 | return true; 87 | } 88 | 89 | public static string GetArg () 90 | { 91 | string arg = ""; 92 | 93 | Logger.Log("e1m1i: " + e1m1i + " e1m2: " + e1m2 + " e1m2i: " + e1m2i); 94 | arg = e1m1; 95 | 96 | // Add Entry 1 97 | if (!string.IsNullOrWhiteSpace(e1m2)) // Check if entry 1 has a second model 98 | arg += $";{e1m1i}&{e1m2};{e1m2i}"; 99 | 100 | // Add Entry 2 101 | if (!string.IsNullOrWhiteSpace(e2m1)) // Check if entry 2 is used 102 | { 103 | arg += $">{e2m1}"; 104 | 105 | if (!string.IsNullOrWhiteSpace(e2m2)) // Check if entry 2 has a second model 106 | arg += $";{e2m1i}&{e2m2};{e2m2i}"; 107 | } 108 | 109 | // Add Entry 3 110 | if (!string.IsNullOrWhiteSpace(e3m1)) // Check if entry 3 is used 111 | { 112 | arg += $">{e3m1}"; 113 | 114 | if (!string.IsNullOrWhiteSpace(e3m2)) // Check if entry 3 has a second model 115 | arg += $";{e3m1i}&{e3m2};{e3m2i}"; 116 | } 117 | 118 | arg = arg.Wrap(true, false); 119 | 120 | return arg; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Code/Main/Dependencies.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.OS; 2 | using Cupscale.UI; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Management; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Cupscale.Main 11 | { 12 | class Dependencies 13 | { 14 | public static bool HasGpu() 15 | { 16 | ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DisplayConfiguration"); 17 | 18 | string graphicsCard = string.Empty; 19 | 20 | foreach (ManagementObject mo in searcher.Get()) 21 | { 22 | foreach (PropertyData property in mo.Properties) 23 | { 24 | if (property.Name == "Description") 25 | { 26 | graphicsCard = property.Value.ToString(); 27 | if (string.IsNullOrWhiteSpace(graphicsCard) || graphicsCard.ToLower().Contains("microsoft")) 28 | return false; 29 | Logger.Log("[DepCheck] Found GPU: " + graphicsCard); 30 | return true; 31 | } 32 | } 33 | } 34 | 35 | Logger.Log("[DepCheck] No GPU found!"); 36 | return false; 37 | } 38 | 39 | public static bool SysPyAvail () 40 | { 41 | string sysPyVer = GetSysPyVersion(); 42 | 43 | if (!string.IsNullOrWhiteSpace(sysPyVer) && !sysPyVer.ToLower().Contains("not found") && sysPyVer.Length <= 35) 44 | return true; 45 | 46 | return false; 47 | } 48 | 49 | public static string GetSysPyVersion() 50 | { 51 | string pythonOut = GetSysPythonOutput(); 52 | Logger.Log("[DepCheck] System Python Check Output: " + pythonOut.Trim()); 53 | 54 | try 55 | { 56 | string ver = pythonOut.Split('(')[0].Trim(); 57 | Logger.Log("[DepCheck] Sys Python Ver: " + ver); 58 | return ver; 59 | } 60 | catch 61 | { 62 | return ""; 63 | } 64 | } 65 | 66 | public static bool EmbedPyAvail() 67 | { 68 | string embedPyVer = GetEmbedPyVersion(); 69 | 70 | if (!string.IsNullOrWhiteSpace(embedPyVer) && !embedPyVer.ToLower().Contains("not found") && embedPyVer.Length <= 35) 71 | return true; 72 | 73 | return false; 74 | } 75 | 76 | public static string GetEmbedPyVersion() 77 | { 78 | string pythonOut = GetEmbedPythonOutput(); 79 | Logger.Log("[DepCheck] Embed Python Check Output: " + pythonOut.Trim()); 80 | 81 | try 82 | { 83 | string ver = pythonOut.Split('(')[0].Trim(); 84 | Logger.Log("[DepCheck] Embed Python Ver: " + ver); 85 | return ver; 86 | } 87 | catch 88 | { 89 | return ""; 90 | } 91 | } 92 | 93 | public static string GetSysPythonOutput() 94 | { 95 | Process py = OsUtils.NewProcess(true); 96 | py.StartInfo.Arguments = "/C python -V"; 97 | Logger.Log("[DepCheck] CMD: " + py.StartInfo.Arguments); 98 | py.Start(); 99 | py.WaitForExit(); 100 | string output = py.StandardOutput.ReadToEnd(); 101 | string err = py.StandardError.ReadToEnd(); 102 | return output + "\n" + err; 103 | } 104 | 105 | public static string GetEmbedPythonOutput() 106 | { 107 | Process py = OsUtils.NewProcess(true); 108 | py.StartInfo.Arguments = "/C " + EmbeddedPython.GetEmbedPyPath().Wrap() + " -V"; 109 | Logger.Log("[DepCheck] CMD: " + py.StartInfo.Arguments); 110 | py.Start(); 111 | py.WaitForExit(); 112 | string output = py.StandardOutput.ReadToEnd(); 113 | string err = py.StandardError.ReadToEnd(); 114 | if (!string.IsNullOrWhiteSpace(err)) output += "\n" + err; 115 | return output; 116 | } 117 | 118 | public static string GetPytorchVer() 119 | { 120 | try 121 | { 122 | Process py = OsUtils.NewProcess(true); 123 | py.StartInfo.Arguments = "\"/C\" " + EmbeddedPython.GetPyCmd() + " -c \"import torch; print(torch.__version__)\""; 124 | Logger.Log("[DepCheck] CMD: " + py.StartInfo.Arguments); 125 | py.Start(); 126 | py.WaitForExit(); 127 | string output = py.StandardOutput.ReadToEnd(); 128 | string err = py.StandardError.ReadToEnd(); 129 | if (!string.IsNullOrWhiteSpace(err)) output += "\n" + err; 130 | Logger.Log("[DepCheck] Pytorch Check Output: " + output.Trim()); 131 | return output; 132 | } 133 | catch 134 | { 135 | return ""; 136 | } 137 | } 138 | 139 | public static string GetOpenCvVer() 140 | { 141 | try 142 | { 143 | Process py = OsUtils.NewProcess(true); 144 | py.StartInfo.Arguments = "\"/C\" " + EmbeddedPython.GetPyCmd() + " -c \"import cv2; print(cv2.__version__)\""; 145 | Logger.Log("[DepCheck] CMD: " + py.StartInfo.Arguments); 146 | py.Start(); 147 | py.WaitForExit(); 148 | string output = py.StandardOutput.ReadToEnd(); 149 | string err = py.StandardError.ReadToEnd(); 150 | if (!string.IsNullOrWhiteSpace(err)) output += "\n" + err; 151 | Logger.Log("[DepCheck] CV2 Check Output: " + output.Trim()); 152 | return output; 153 | } 154 | catch 155 | { 156 | return ""; 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Code/Main/EsrganData.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.Forms; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Windows.Forms; 5 | 6 | namespace Cupscale 7 | { 8 | internal class EsrganData 9 | { 10 | public static List models = new List(); 11 | public static List modelsFullPath = new List(); 12 | 13 | public static void CheckModelDir() 14 | { 15 | if (string.IsNullOrWhiteSpace(Config.Get("modelPath"))) 16 | { 17 | Program.ShowMessage("Please set a model path in the settings.\nPoint it to the folder where you save your .pth model files.", "Notice"); 18 | new SettingsForm().ShowDialog(); 19 | } 20 | else if (!Directory.Exists(Config.Get("modelPath"))) 21 | { 22 | Program.ShowMessage("The model path you entered isn't valid!", "Notice"); 23 | new SettingsForm().ShowDialog(); 24 | } 25 | } 26 | 27 | public static bool ModelExists (string modelName) 28 | { 29 | string[] files = Directory.GetFiles("*.pth", Config.Get("modelPath"), SearchOption.AllDirectories); 30 | foreach(string modelFile in files) 31 | { 32 | if (Path.GetFileNameWithoutExtension(modelFile) == modelName) 33 | return true; 34 | } 35 | return false; 36 | } 37 | 38 | public static void ReloadModelList() 39 | { 40 | string mdlPath = Config.Get("modelPath"); 41 | if (!Directory.Exists(mdlPath)) 42 | { 43 | Logger.Log("[EsrganData] Model dir doesn't exist!"); 44 | return; 45 | } 46 | models.Clear(); 47 | modelsFullPath.Clear(); 48 | string[] files = Directory.GetFiles(mdlPath); 49 | string[] array = files; 50 | foreach (string path in array) 51 | { 52 | string fileName = Path.GetFileName(path); 53 | if (fileName.EndsWith(".pth")) 54 | { 55 | models.Add(fileName.Replace(".pth", "")); 56 | modelsFullPath.Add(path); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Code/Main/GeneralOutputHandler.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.UI; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Cupscale.Main 9 | { 10 | class GeneralOutputHandler 11 | { 12 | public enum ProcessType { Generic, Python, Ncnn } 13 | 14 | public static void HandleImpErrorMsgs(string log, ProcessType processType = ProcessType.Generic) 15 | { 16 | bool errored = false; 17 | 18 | if (processType == ProcessType.Ncnn) 19 | { 20 | if (!errored && log.Contains("vkAllocateMemory")) 21 | { 22 | Program.Cancel("NCNN ran out of memory.\nTry reducing the tile size and avoid " + 23 | "running programs in the background (especially games) that take up your VRAM."); 24 | errored = true; 25 | } 26 | 27 | if (!errored && log.Contains("vkWaitForFences")) 28 | { 29 | Program.Cancel("NCNN crashed!\nMake sure your GPU drivers are up to date, try reducing the tile size and avoid " + 30 | "running programs in the background (especially games) that take up your VRAM."); 31 | errored = true; 32 | } 33 | } 34 | 35 | if (processType == ProcessType.Python) 36 | { 37 | if (log.ToLower().Contains("out of memory")) 38 | { 39 | Program.ShowMessage("ESRGAN ran out of memory. Try reducing the tile size and avoid running programs in the background (especially games) that take up your VRAM.", "Error"); 40 | errored = true; 41 | } 42 | 43 | if (log.Contains("Python was not found")) 44 | { 45 | Program.Cancel("Python was not found. Make sure you have a working Python 3 installation, or use the embedded runtime."); 46 | errored = true; 47 | } 48 | 49 | if (log.Contains("ModuleNotFoundError")) 50 | { 51 | Program.Cancel("You are missing Python dependencies. Make sure Pytorch and cv2 (opencv-python) are installed."); 52 | errored = true; 53 | } 54 | 55 | if (log.Contains("RRDBNet")) 56 | { 57 | Program.Cancel("Model appears to be incompatible!"); 58 | errored = true; 59 | } 60 | 61 | if (log.Contains("UnpicklingError")) 62 | { 63 | Program.Cancel("Failed to load model!\nPossibly it's corrupted or in an unknown format."); 64 | errored = true; 65 | } 66 | 67 | if (log.Contains("must match the size of tensor") || log.Contains("KeyError: 'model.") || log.Contains("KeyError: 'conv_first.weight'")) 68 | { 69 | Program.Cancel("It seems like you tried to load or interpolate incompatible models!"); 70 | errored = true; 71 | } 72 | 73 | if (log.Contains("not implemented for 'Half'")) 74 | { 75 | Program.Cancel("A half-precision problem occured. Try to run this implementation without half-precision enabled."); 76 | errored = true; 77 | } 78 | } 79 | 80 | //if (!errored && log.Contains("failed")) 81 | //{ 82 | // Program.Cancel($"Error occurred while running AI implementation: \n\n{log}\n\n"); 83 | // errored = true; 84 | //} 85 | 86 | if (errored) 87 | Program.Cancel(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Code/Main/Logger.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.Forms; 2 | using System; 3 | using System.IO; 4 | using System.Windows.Forms; 5 | using Cupscale.IO; 6 | using DT = System.DateTime; 7 | 8 | namespace Cupscale 9 | { 10 | internal class Logger 11 | { 12 | public static TextBox textbox; 13 | 14 | public static string sessionLog; 15 | 16 | public static string file; 17 | 18 | public static bool disable; 19 | 20 | public static bool doLogIo; 21 | public static bool doLogStatus; 22 | 23 | public static void Init () 24 | { 25 | file = Path.Combine(Paths.GetDataPath(), "sessionlog.txt"); 26 | doLogIo = Config.GetBool("logIo"); 27 | doLogStatus = Config.GetBool("logStatus"); 28 | PrintArgs(); 29 | } 30 | 31 | public static void PrintArgs () 32 | { 33 | foreach (string arg in Environment.GetCommandLineArgs()) 34 | Log("Arg: " + arg); 35 | } 36 | 37 | public static void Log(string s, bool logToFile = true, bool noLineBreak = false, bool replaceLastLine = false) 38 | { 39 | if (disable) return; 40 | 41 | Console.WriteLine(s); 42 | 43 | if (replaceLastLine) 44 | { 45 | textbox.Text = textbox.Text.Remove(textbox.Text.LastIndexOf(Environment.NewLine)); 46 | sessionLog = sessionLog.Remove(sessionLog.LastIndexOf(Environment.NewLine)); 47 | } 48 | 49 | if(!noLineBreak) 50 | sessionLog += Environment.NewLine + s; 51 | else 52 | sessionLog += " " + s; 53 | 54 | if (logToFile) 55 | LogToFile(s, noLineBreak); 56 | } 57 | 58 | public static void LogToFile(string s, bool noLineBreak) 59 | { 60 | if (string.IsNullOrWhiteSpace(file)) 61 | file = Path.Combine(Paths.GetDataPath(), "sessionlog.txt"); 62 | string time = DT.Now.Month + "-" + DT.Now.Day + "-" + DT.Now.Year + " " + DT.Now.Hour + ":" + DT.Now.Minute + ":" + DT.Now.Second; 63 | 64 | try 65 | { 66 | if (!noLineBreak) 67 | File.AppendAllText(file, Environment.NewLine + time + ": " + s); 68 | else 69 | File.AppendAllText(file, " " + s); 70 | } 71 | catch 72 | { 73 | // idk how to deal with this race condition (?) but just ignoring it seems to work lol 74 | } 75 | } 76 | 77 | public static string GetSessionLog () 78 | { 79 | return sessionLog; 80 | } 81 | 82 | public static MsgBox ErrorMessage (string msg, Exception e) 83 | { 84 | string text = $"{msg}\n\n{e.Message}\n\nStack Trace:\n{e.StackTrace}"; 85 | Clipboard.SetText(text); 86 | Log(text); 87 | return Program.ShowMessage(text + "\n\nThe error message was copied to the clipboard.", "Error"); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Code/Main/MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | Use "Tile" or "Mirror" for seamless/tiled textures. 125 | "Extend" will stretch the last pixel row on each side to avoid seams on the borders of the image. 126 | "Alpha" will surround the image with transparency to avoid pixels being squashed to the border of the image. 127 | 128 | 129 | 34 130 | 131 | -------------------------------------------------------------------------------- /Code/Main/PostProcessing.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.IO; 2 | using Cupscale.UI; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows; 10 | using System.Windows.Forms; 11 | 12 | namespace Cupscale.Main 13 | { 14 | class PostProcessing 15 | { 16 | public static async Task PostprocessingSingle(string path, bool dontResize = false, int retryCount = 20, bool trimPngExt = true) 17 | { 18 | if (!IoUtils.IsFileValid(path)) 19 | return; 20 | 21 | string newPath = ""; 22 | 23 | if (trimPngExt) 24 | newPath = path.Substring(0, path.Length - 4); 25 | 26 | Logger.Log($"PostProc: Trimmed filename from '{Path.GetFileName(path)}' to '{Path.GetFileName(newPath)}'"); 27 | 28 | try 29 | { 30 | File.Move(path, newPath); 31 | } 32 | catch (Exception e) // An I/O error can appear if the file is still locked by python (?) 33 | { 34 | Logger.Log($"Failed to move/rename! ('{path}' => '{newPath}') {e.Message}\n{e.StackTrace}"); 35 | 36 | if (retryCount > 0) 37 | { 38 | await Task.Delay(500); // Wait and retry up to 20 times 39 | int newRetryCount = retryCount - 1; 40 | Logger.Log("Retrying - " + newRetryCount + " attempts left."); 41 | await PostprocessingSingle(path, dontResize, newRetryCount); 42 | } 43 | else 44 | { 45 | Logger.ErrorMessage($"Failed to move/rename '{Path.GetFileName(path)}' and ran out of retries!", e); 46 | } 47 | 48 | return; 49 | } 50 | 51 | path = newPath; 52 | string format = PreviewUi.outputFormat.Text; 53 | 54 | if (Program.lastUpscaleIsVideo || format == Upscale.ImgExportMode.PNG.ToStringTitleCase()) 55 | { 56 | await ImageProcessing.PostProcessImage(path, ImageProcessing.Format.Png50, dontResize); 57 | return; 58 | } 59 | 60 | if (format == Upscale.ImgExportMode.SameAsSource.ToStringTitleCase()) 61 | await ImageProcessing.ConvertImageToOriginalFormat(path, true, false, dontResize); 62 | 63 | if (format == Upscale.ImgExportMode.JPEG.ToStringTitleCase()) 64 | await ImageProcessing.PostProcessImage(path, ImageProcessing.Format.Jpeg, dontResize); 65 | 66 | if (format == Upscale.ImgExportMode.WEBP.ToStringTitleCase()) 67 | await ImageProcessing.PostProcessImage(path, ImageProcessing.Format.Weppy, dontResize); 68 | 69 | if (format == Upscale.ImgExportMode.BMP.ToStringTitleCase()) 70 | await ImageProcessing.PostProcessImage(path, ImageProcessing.Format.BMP, dontResize); 71 | 72 | if (format == Upscale.ImgExportMode.TGA.ToStringTitleCase()) 73 | await ImageProcessing.PostProcessImage(path, ImageProcessing.Format.TGA, dontResize); 74 | 75 | if (format == Upscale.ImgExportMode.DDS.ToStringTitleCase()) 76 | await ImageProcessing.PostProcessDDS(path); 77 | 78 | if (format == Upscale.ImgExportMode.GIF.ToStringTitleCase()) 79 | await ImageProcessing.PostProcessImage(path, ImageProcessing.Format.GIF, dontResize); 80 | 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Code/Main/PostProcessingQueue.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.IO; 2 | using Cupscale.Main; 3 | using Cupscale.UI; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace Cupscale.Cupscale 13 | { 14 | class PostProcessingQueue 15 | { 16 | public static Queue outputFileQueue = new Queue(); 17 | public static List processedFiles = new List(); 18 | public static List outputFiles = new List(); 19 | 20 | public static bool run; 21 | public static string currentOutPath; 22 | 23 | //public static bool ncnn; 24 | 25 | public enum CopyMode { KeepStructure, CopyToRoot } 26 | public static CopyMode copyMode; 27 | 28 | public static void Start (string outpath) 29 | { 30 | Logger.Log("[Queue] Start()"); 31 | currentOutPath = outpath; 32 | outputFileQueue.Clear(); 33 | processedFiles.Clear(); 34 | outputFiles.Clear(); 35 | IoUtils.ClearDir(Paths.imgOutPath); 36 | run = true; 37 | } 38 | 39 | public static void Stop () 40 | { 41 | Logger.Log("[Queue] Stop()"); 42 | run = false; 43 | } 44 | 45 | public static async Task Update () 46 | { 47 | while (run || AnyFilesLeft()) 48 | { 49 | CheckNcnnOutput(); 50 | string[] outFiles = Directory.GetFiles(Paths.imgOutPath, "*.tmp", SearchOption.AllDirectories); 51 | 52 | foreach (string file in outFiles) 53 | { 54 | if (!outputFileQueue.Contains(file) && !processedFiles.Contains(file) && !outputFiles.Contains(file)) 55 | { 56 | //processedFiles.Add(file); 57 | outputFileQueue.Enqueue(file); 58 | Logger.Log("[Queue] Enqueued " + Path.GetFileName(file)); 59 | } 60 | } 61 | 62 | await Task.Delay(1000); 63 | } 64 | } 65 | 66 | static bool AnyFilesLeft () 67 | { 68 | if (IoUtils.GetAmountOfFiles(Paths.imgOutPath, true) > 0) 69 | return true; 70 | 71 | return false; 72 | } 73 | 74 | public static string lastOutfile; 75 | 76 | public static async Task ProcessQueue () 77 | { 78 | Stopwatch sw = new Stopwatch(); 79 | 80 | while (!Program.canceled && (run || AnyFilesLeft())) 81 | { 82 | if (outputFileQueue.Count > 0) 83 | { 84 | string file = outputFileQueue.Dequeue(); 85 | Logger.Log("[Queue] Post-Processing " + Path.GetFileName(file)); 86 | sw.Restart(); 87 | await PostProcessing.PostprocessingSingle(file, false); 88 | 89 | while (IoUtils.IsFileLocked(lastOutfile)) 90 | { 91 | Logger.Log($"{file} appears to be locked - waiting 500ms..."); 92 | await Task.Delay(500); 93 | } 94 | 95 | string outFilename = Upscale.FilenamePostprocess(lastOutfile); 96 | 97 | if(outFilename == null) 98 | { 99 | Logger.Log($"[Queue] Error: Upscale.FilenamePostprocess({lastOutfile}) returned null!"); 100 | return; 101 | } 102 | 103 | outputFiles.Add(outFilename); 104 | Logger.Log("[Queue] Done Post-Processing " + Path.GetFileName(file) + " in " + sw.ElapsedMilliseconds + "ms"); 105 | 106 | try 107 | { 108 | if (Upscale.overwriteMode == Upscale.Overwrite.Yes) 109 | { 110 | string suffixToRemove = "-" + Program.lastModelName.Replace(":", ".").Replace(">>", "+"); 111 | 112 | if (copyMode == CopyMode.KeepStructure) 113 | { 114 | string combinedPath = currentOutPath + outFilename.Replace(Paths.imgOutPath, ""); 115 | Directory.CreateDirectory(combinedPath.GetParentDir()); 116 | File.Copy(outFilename, combinedPath.ReplaceInFilename(suffixToRemove, "", true), true); 117 | } 118 | if (copyMode == CopyMode.CopyToRoot) 119 | { 120 | File.Copy(outFilename, Path.Combine(currentOutPath, Path.GetFileName(outFilename).Replace(suffixToRemove, "")), true); 121 | } 122 | 123 | File.Delete(outFilename); 124 | } 125 | else 126 | { 127 | if (copyMode == CopyMode.KeepStructure) 128 | { 129 | string combinedPath = currentOutPath + outFilename.Replace(Paths.imgOutPath, ""); 130 | Directory.CreateDirectory(combinedPath.GetParentDir()); 131 | File.Copy(outFilename, combinedPath, true); 132 | } 133 | 134 | if (copyMode == CopyMode.CopyToRoot) 135 | { 136 | File.Copy(outFilename, Path.Combine(currentOutPath, Path.GetFileName(outFilename)), true); 137 | } 138 | 139 | File.Delete(outFilename); 140 | } 141 | } 142 | catch (Exception e) 143 | { 144 | Logger.Log("Error trying to copy post-processed file back: " + e.Message + "\n" + e.StackTrace); 145 | } 146 | 147 | BatchUpscaleUI.upscaledImages++; 148 | } 149 | 150 | await Task.Delay(200); 151 | } 152 | } 153 | 154 | static void CheckNcnnOutput() 155 | { 156 | foreach (string file in Directory.GetFiles(Paths.imgOutPath, "*.*.png", SearchOption.AllDirectories)) // Rename to tmp 157 | { 158 | try 159 | { 160 | string newPath = file.Substring(0, file.Length - 8) + ".tmp"; 161 | string movePath = Path.Combine(Paths.imgOutPath, Path.GetFileName(newPath)); 162 | Logger.Log("[Queue] Renaming & moving " + file + " => " + movePath); 163 | File.Move(file, movePath); 164 | } 165 | catch { } 166 | } 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Code/Main/PreviewState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Cupscale.Cupscale 9 | { 10 | public struct PreviewState 11 | { 12 | public Image image; 13 | public int zoom; 14 | public Point autoScrollPosition; 15 | 16 | public PreviewState (Image img, int currentZoom, Point autoScrollPos) 17 | { 18 | image = img; 19 | zoom = currentZoom; 20 | autoScrollPosition = autoScrollPos; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Code/Main/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows.Forms; 9 | using Cupscale.Forms; 10 | using Cupscale.ImageUtils; 11 | using Cupscale.IO; 12 | using Cupscale.Main; 13 | using Cupscale.OS; 14 | using Cupscale.UI; 15 | using ImageMagick; 16 | using Win32Interop.Enums; 17 | using Paths = Cupscale.IO.Paths; 18 | 19 | [assembly: System.Windows.Media.DisableDpiAwareness] // Disable Dpi awareness in the application assembly. 20 | 21 | namespace Cupscale 22 | { 23 | internal static class Program 24 | { 25 | public static MainForm mainForm; 26 | public static string lastOutputDir; 27 | public static string lastImgPath; // Single Image 28 | public static string lastDirPath; // Batch 29 | public static string lastVidPath; // Video 30 | public static string lastModelName; 31 | public static string currentModel1; 32 | public static string currentModel2; 33 | public static FilterType currentFilter = FilterType.Point; 34 | 35 | public static List
currentTemporaryForms = new List(); // Temp forms that get closed when something gets cancelled 36 | public static List openMessageBoxes = new List(); // Temp forms that get closed when something gets cancelled 37 | 38 | public static bool lastUpscaleIsVideo; 39 | public static Process lastImpProcess; 40 | public static bool canceled = false; 41 | 42 | public static bool busy; 43 | 44 | [STAThread] 45 | private static void Main() 46 | { 47 | try 48 | { 49 | string lockfile = Path.Combine(Paths.GetDataPath(), "lockfile"); 50 | File.Create(lockfile).Dispose(); 51 | FileStream fs = File.Open(lockfile, FileMode.Open, FileAccess.ReadWrite, FileShare.None); 52 | } 53 | catch 54 | { 55 | MessageBox.Show("Another instance of Cupscale seems to be running, accessing the following data folder:\n" 56 | + Paths.GetDataPath() + ".\n\nMultiple instance are only possible if they use different data folders.\n" 57 | + "Starting Cupscale with \"-portable\" will use the current directory as data folder.", "Error"); 58 | return; 59 | } 60 | 61 | Application.SetCompatibleTextRenderingDefault(defaultValue: false); 62 | Application.EnableVisualStyles(); 63 | IoUtils.DeleteIfExists(Path.Combine(Paths.GetDataPath(), "sessionlog.txt")); 64 | Config.Init(); 65 | Logger.Init(); 66 | Paths.Init(); 67 | AddBinsToPath(); 68 | Implementations.Imps.Init(); 69 | ResourceLimits.Memory = (ulong)Math.Round(ResourceLimits.Memory * 1.5f); 70 | Cleanup(); 71 | Application.Run(new MainForm()); 72 | } 73 | 74 | private static void AddBinsToPath () 75 | { 76 | string path = Environment.GetEnvironmentVariable("PATH"); 77 | Environment.SetEnvironmentVariable($"PATH", path + $";{Paths.binPath}"); 78 | } 79 | 80 | public static void Cancel (string reason = "", bool cleanup = true) 81 | { 82 | canceled = true; 83 | OsUtils.KillProcessTree(lastImpProcess); 84 | 85 | mainForm.SetProgress(0, "Canceled."); 86 | mainForm.SetBusy(false); 87 | 88 | if (reason.Trim().Length > 0) 89 | ShowMessage(reason); 90 | 91 | if (cleanup) 92 | { 93 | IoUtils.ClearDir(Paths.imgInPath); 94 | IoUtils.ClearDir(Paths.imgOutPath); 95 | } 96 | } 97 | 98 | public static MsgBox ShowMessage(string msg, string title = "Message") 99 | { 100 | DialogQueue.Init(); 101 | MsgBox msgBox = new MsgBox(msg.Replace("\n", Environment.NewLine), title); 102 | DialogQueue.ShowDialog(msgBox); 103 | return msgBox; 104 | } 105 | 106 | public static void Cleanup() 107 | { 108 | try 109 | { 110 | IoUtils.ClearDir(Paths.previewPath); 111 | IoUtils.ClearDir(Paths.previewOutPath); 112 | IoUtils.ClearDir(Paths.clipboardFolderPath); 113 | IoUtils.ClearDir(Paths.imgInPath); 114 | IoUtils.ClearDir(Paths.imgOutPath); 115 | IoUtils.ClearDir(Paths.tempImgPath.GetParentDir()); 116 | IoUtils.ClearDir(Path.Combine(Paths.GetDataPath(), "giftemp")); 117 | IoUtils.DeleteIfExists(Path.Combine(Paths.presetsPath, "lastUsed")); 118 | IoUtils.ClearDir(Paths.compositionOut); 119 | IoUtils.ClearDir(Paths.framesOutPath); 120 | IoUtils.DeleteIfExists(Path.Combine(Paths.GetDataPath(), "frames-out.mp4")); 121 | } 122 | catch (Exception e) 123 | { 124 | Logger.Log("Error during cleanup: " + e.Message); 125 | } 126 | } 127 | 128 | public static void CloseTempForms() 129 | { 130 | foreach (Form form in currentTemporaryForms.ToList()) 131 | form.Close(); 132 | } 133 | 134 | public static async Task PutTaskDelay() 135 | { 136 | await Task.Delay(1); 137 | } 138 | 139 | public static int GetPercentage(float val1, float val2) 140 | { 141 | return (int)Math.Round((val1 / val2) * 100f); 142 | } 143 | 144 | public static void Quit() 145 | { 146 | Application.Exit(); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /Code/Main/Servers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.NetworkInformation; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | 9 | namespace Cupscale.Main 10 | { 11 | class Servers 12 | { 13 | public static Server hetznerEu = new Server { name = "Germany (Nürnberg)", host = "nmkd-hz.de", pattern = "https://dl.*" }; 14 | public static Server contaboUs = new Server { name = "USA (St. Louis)", host = "nmkd-cb.de", pattern = "https://dl.*" }; 15 | 16 | public static List serverList = new List { hetznerEu, contaboUs }; 17 | 18 | public static Server closestServer = serverList[0]; 19 | 20 | public class Server 21 | { 22 | public string name = ""; 23 | public string host = ""; 24 | public string pattern = "*"; 25 | 26 | public string GetUrl() 27 | { 28 | return pattern.Replace("*", host); 29 | } 30 | } 31 | 32 | public static async Task Init(ComboBox comboBox = null) 33 | { 34 | Dictionary serversPings = new Dictionary(); 35 | 36 | foreach (Server server in serverList) 37 | { 38 | try 39 | { 40 | Ping p = new Ping(); 41 | PingReply replyEur = p.Send(server.host, 2000); 42 | serversPings[new string[] { server.name, server.host, server.pattern }] = replyEur.RoundtripTime; 43 | Logger.Log($"[Servers] Ping to {server.host}: {replyEur.RoundtripTime} ms", true); 44 | } 45 | catch (Exception e) 46 | { 47 | Logger.Log($"[Servers] Failed to ping {server.host}: {e.Message}", true); 48 | serversPings[new string[] { server.name, server.host, server.pattern }] = 10000; 49 | } 50 | } 51 | 52 | var closest = serversPings.Aggregate((l, r) => l.Value < r.Value ? l : r); 53 | Logger.Log($"[Servers] Closest Server: {closest.Key[0]} ({closest.Value} ms)", true); 54 | closestServer = new Server { name = closest.Key[0], host = closest.Key[1], pattern = closest.Key[2] }; 55 | 56 | if (comboBox != null) 57 | { 58 | for (int i = 0; i < comboBox.Items.Count; i++) 59 | { 60 | if (comboBox.Items[i].ToString() == closestServer.name) 61 | comboBox.SelectedIndex = i; 62 | } 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Code/OS/NcnnUtils.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.Forms; 2 | using Cupscale.ImageUtils; 3 | using Cupscale.Implementations; 4 | using Cupscale.IO; 5 | using Cupscale.UI; 6 | using System; 7 | using System.Diagnostics; 8 | using System.Drawing; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Linq.Expressions; 12 | using System.Threading.Tasks; 13 | using System.Windows.Forms; 14 | 15 | namespace Cupscale.OS 16 | { 17 | class NcnnUtils 18 | { 19 | public static string currentNcnnModel; 20 | public static string lastNcnnOutput; 21 | static Process currentProcess; 22 | static string ncnnDir = ""; 23 | private static string ConverterDir { get => Path.Combine(Paths.binPath, "pth2ncnn"); } 24 | 25 | public static async Task ConvertNcnnModel(string modelPath, string filenamePattern) 26 | { 27 | Logger.Log($"ConvertNcnnModel: {modelPath}"); 28 | 29 | try 30 | { 31 | if (IsDirNcnnModel(modelPath)) 32 | { 33 | ApplyFilenamePattern(modelPath, filenamePattern); 34 | currentNcnnModel = modelPath; 35 | return; 36 | } 37 | 38 | string modelName = Path.GetFileName(modelPath); 39 | ncnnDir = Path.Combine(Config.Get("modelPath"), ".ncnn-models"); 40 | Directory.CreateDirectory(ncnnDir); 41 | string outPath = Path.Combine(ncnnDir, Path.ChangeExtension(modelName, null)); 42 | Logger.Log("Checking for NCNN model: " + outPath); 43 | 44 | if (IoUtils.GetAmountOfFiles(outPath, false) < 2) 45 | { 46 | Logger.Log("Running model converter..."); 47 | DialogForm dialog = new DialogForm("Converting ESRGAN model to NCNN format..."); 48 | await RunConverter(modelPath); 49 | 50 | if (lastNcnnOutput.Contains("Error:")) 51 | throw new Exception(lastNcnnOutput.SplitIntoLines().Where(x => x.Contains("Error:")).First()); 52 | 53 | string moveFrom = Path.Combine(ConverterDir, Path.ChangeExtension(modelName, null)); 54 | Logger.Log("Moving " + moveFrom + " to " + outPath); 55 | await IoUtils.CopyDir(moveFrom, outPath, "*", true); 56 | Directory.Delete(moveFrom, true); 57 | dialog.Close(); 58 | } 59 | else 60 | { 61 | Logger.Log("NCNN Model is cached - Skipping conversion."); 62 | } 63 | 64 | ApplyFilenamePattern(outPath, filenamePattern); 65 | currentNcnnModel = outPath; 66 | } 67 | catch (Exception e) 68 | { 69 | Logger.ErrorMessage("Failed to convert Pytorch model to NCNN format! It might be incompatible.", e); 70 | } 71 | } 72 | 73 | static void ApplyFilenamePattern(string path, string pattern) 74 | { 75 | foreach (FileInfo file in IoUtils.GetFileInfosSorted(path).Where(f => f.Extension == ".bin" || f.Extension == ".param")) 76 | IoUtils.RenameFile(file.FullName, pattern.Replace("*", $"{file.Name.GetInt()}")); 77 | } 78 | 79 | static async Task RunConverter(string modelPath) 80 | { 81 | lastNcnnOutput = ""; 82 | bool showWindow = Config.GetInt("cmdDebugMode") > 0; 83 | bool stayOpen = Config.GetInt("cmdDebugMode") == 2; 84 | 85 | modelPath = modelPath.Wrap(); 86 | 87 | string opt = "/C"; 88 | if (stayOpen) opt = "/K"; 89 | 90 | string args = $"{opt} cd /D {ConverterDir.Wrap()} & pth2ncnn.exe {modelPath}"; 91 | 92 | Logger.Log("[CMD] " + args); 93 | Process converterProc = OsUtils.NewProcess(!showWindow); 94 | converterProc.StartInfo.Arguments = args; 95 | 96 | if (!showWindow) 97 | { 98 | converterProc.OutputDataReceived += OutputHandler; 99 | converterProc.ErrorDataReceived += OutputHandler; 100 | } 101 | 102 | currentProcess = converterProc; 103 | converterProc.Start(); 104 | 105 | if (!showWindow) 106 | { 107 | converterProc.BeginOutputReadLine(); 108 | converterProc.BeginErrorReadLine(); 109 | } 110 | 111 | while (!converterProc.HasExited) 112 | await Task.Delay(100); 113 | } 114 | 115 | private static void OutputHandler(object sendingProcess, DataReceivedEventArgs output) 116 | { 117 | if (output == null || output.Data == null) 118 | return; 119 | 120 | string data = output.Data; 121 | Logger.Log("[NcnnUtils] Model Converter Output: " + data); 122 | lastNcnnOutput += $"{data}\n"; 123 | } 124 | 125 | public static bool IsDirNcnnModel (string path, bool requireSuffix = true, bool noMoreThanTwoFiles = false) 126 | { 127 | try 128 | { 129 | if (!IoUtils.IsPathDirectory(path)) 130 | return false; 131 | 132 | DirectoryInfo dir = new DirectoryInfo(path); 133 | bool suffixValid = dir.Name.EndsWith(".ncnn"); 134 | bool filesValid = dir.GetFiles("*.bin").Length == 1 && dir.GetFiles("*.param").Length == 1; 135 | 136 | if (noMoreThanTwoFiles && dir.GetFiles("*").Length > 2) 137 | filesValid = false; 138 | 139 | if (requireSuffix && !suffixValid) 140 | return false; 141 | 142 | return filesValid; 143 | } 144 | catch(Exception e) 145 | { 146 | Logger.Log($"IsDirNcnnModel Exception: {e.Message}. Defaulting to false."); 147 | return false; 148 | } 149 | } 150 | 151 | public static int GetNcnnModelScale(string modelDir) 152 | { 153 | try 154 | { 155 | string[] files = Directory.GetFiles(modelDir, "*.bin"); 156 | return Path.GetFileNameWithoutExtension(files[0]).GetInt(); 157 | } 158 | catch (Exception e) 159 | { 160 | Logger.Log($"Failed to get NCNN model scale for dir '{modelDir}': {e.Message}"); 161 | return 4; 162 | } 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /Code/OS/NvApi.cs: -------------------------------------------------------------------------------- 1 | using NvAPIWrapper; 2 | using NvAPIWrapper.GPU; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace Cupscale.OS 12 | { 13 | class NvApi 14 | { 15 | public enum Architecture { Undetected, Fermi, Kepler, Maxwell, Pascal, Turing, Ampere }; 16 | public static List gpuList = new List(); 17 | 18 | public static async void Init () 19 | { 20 | try 21 | { 22 | NVIDIA.Initialize(); 23 | PhysicalGPU[] gpus = PhysicalGPU.GetPhysicalGPUs(); 24 | 25 | if (gpus.Length == 0) 26 | return; 27 | 28 | gpuList = gpus.ToList(); 29 | List gpuNames = new List(); 30 | 31 | foreach (PhysicalGPU gpu in gpus) 32 | Logger.Log($"Detected Card: {gpu.FullName} / GPU: {gpu.ArchitectInformation.ShortName} / Arch: {GetArch(gpu)}"); 33 | 34 | Logger.Log($"Initialized Nvidia API. GPU{(gpus.Length > 1 ? "s" : "")}: {GetGpuListStr()}"); 35 | 36 | while (true) 37 | { 38 | RefreshVram(); 39 | await Task.Delay(1000); 40 | } 41 | } 42 | catch (Exception e) 43 | { 44 | Logger.Log($"Failed to initialize NvApi: {e.Message}\nIgnore this if you don't have an Nvidia GPU."); 45 | } 46 | } 47 | 48 | public static string GetGpuListStr () 49 | { 50 | return string.Join(", ", gpuList.Select(x => x.FullName)); 51 | } 52 | 53 | public static bool HasAmpereOrNewer() // To detect if newer Pytorch version is needed 54 | { 55 | return false; // TODO: REMOVE ME 56 | 57 | foreach (PhysicalGPU gpu in gpuList) 58 | { 59 | Architecture arch = GetArch(gpu); 60 | 61 | if (arch == Architecture.Ampere || arch == Architecture.Undetected) 62 | return true; 63 | } 64 | 65 | return false; 66 | } 67 | 68 | public static Architecture GetArch(PhysicalGPU gpu) 69 | { 70 | string gpuCode = gpu.ArchitectInformation.ShortName; 71 | 72 | if (gpuCode.Trim().StartsWith("GF")) return Architecture.Fermi; 73 | if (gpuCode.Trim().StartsWith("GK")) return Architecture.Kepler; 74 | if (gpuCode.Trim().StartsWith("GM")) return Architecture.Maxwell; 75 | if (gpuCode.Trim().StartsWith("GP")) return Architecture.Pascal; 76 | if (gpuCode.Trim().StartsWith("TU")) return Architecture.Turing; 77 | if (gpuCode.Trim().StartsWith("GA")) return Architecture.Ampere; 78 | 79 | return Architecture.Undetected; 80 | } 81 | 82 | public static void RefreshVram () 83 | { 84 | if (Form.ActiveForm != Program.mainForm) // Don't refresh if not in focu 85 | return; 86 | 87 | List gpusWithVram = new List(); 88 | 89 | foreach(PhysicalGPU gpu in gpuList) 90 | { 91 | if (gpu == null) 92 | continue; 93 | 94 | float vramGb = (gpu.MemoryInformation.AvailableDedicatedVideoMemoryInkB / 1000f / 1024f); 95 | float vramFreeGb = (gpu.MemoryInformation.CurrentAvailableDedicatedVideoMemoryInkB / 1000f / 1024f); 96 | string shortenedName = gpu.FullName.Replace("NVIDIA ", "").Replace("AMD ", ""); 97 | 98 | gpusWithVram.Add($"{shortenedName}: {vramFreeGb.ToString("0.0")}/{vramGb.ToString("0.0")} GB Free"); 99 | } 100 | 101 | Program.mainForm.SetVramLabel(string.Join(" - ", gpusWithVram), Color.White); 102 | } 103 | 104 | public static string GetFirstGpuName () 105 | { 106 | try 107 | { 108 | NVIDIA.Initialize(); 109 | PhysicalGPU[] gpus = PhysicalGPU.GetPhysicalGPUs(); 110 | 111 | if (gpus.Length == 0) 112 | return ""; 113 | 114 | return gpus[0].FullName; 115 | } 116 | catch 117 | { 118 | return ""; 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Code/OS/OSUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text; 3 | using System.Security.Principal; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Management; 7 | 8 | namespace Cupscale.OS 9 | { 10 | class OsUtils 11 | { 12 | public static bool IsUserAdministrator() 13 | { 14 | //bool value to hold our return value 15 | bool isAdmin; 16 | WindowsIdentity user = null; 17 | try 18 | { 19 | //get the currently logged in user 20 | user = WindowsIdentity.GetCurrent(); 21 | WindowsPrincipal principal = new WindowsPrincipal(user); 22 | isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator); 23 | } 24 | catch (UnauthorizedAccessException ex) 25 | { 26 | isAdmin = false; 27 | } 28 | catch (Exception ex) 29 | { 30 | isAdmin = false; 31 | } 32 | finally 33 | { 34 | if (user != null) 35 | user.Dispose(); 36 | } 37 | return isAdmin; 38 | } 39 | 40 | //public enum ProcessMode { Visible } 41 | public static Process SetStartInfo (Process proc, bool hidden, string filename = "cmd.exe") 42 | { 43 | proc.StartInfo.UseShellExecute = !hidden; 44 | proc.StartInfo.RedirectStandardOutput = hidden; 45 | proc.StartInfo.RedirectStandardError = hidden; 46 | proc.StartInfo.CreateNoWindow = hidden; 47 | proc.StartInfo.FileName = filename; 48 | return proc; 49 | } 50 | 51 | public static Process NewProcess(bool hidden, string filename = "cmd.exe") 52 | { 53 | Process proc = new Process(); 54 | return SetStartInfo(proc, hidden, filename); 55 | } 56 | 57 | public static void KillProcessTree(Process proc) 58 | { 59 | if (proc != null) 60 | KillProcessTree(proc.Id); 61 | } 62 | 63 | public static void KillProcessTree(int pid) 64 | { 65 | try 66 | { 67 | ManagementObjectSearcher processSearcher = new ManagementObjectSearcher ("Select * From Win32_Process Where ParentProcessID=" + pid); 68 | ManagementObjectCollection processCollection = processSearcher.Get(); 69 | 70 | Process proc = Process.GetProcessById(pid); 71 | if (!proc.HasExited) proc.Kill(); 72 | 73 | if (processCollection != null) 74 | { 75 | foreach (ManagementObject mo in processCollection) 76 | { 77 | KillProcessTree(Convert.ToInt32(mo["ProcessID"])); //kill child processes(also kills childrens of childrens etc.) 78 | } 79 | } 80 | } 81 | catch 82 | { 83 | // has probably exited already 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Code/Preview/PreviewMerger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Drawing2D; 4 | using System.IO; 5 | using System.Windows; 6 | using Cupscale.ImageUtils; 7 | using Cupscale.IO; 8 | using Cupscale.Main; 9 | using Cupscale.UI; 10 | using ImageMagick; 11 | using Paths = Cupscale.IO.Paths; 12 | 13 | namespace Cupscale 14 | { 15 | internal class PreviewMerger 16 | { 17 | public static float offsetX; 18 | public static float offsetY; 19 | public static string inputCutoutPath; 20 | public static string outputCutoutPath; 21 | 22 | public static bool showingOriginal = false; 23 | 24 | public static void Merge() 25 | { 26 | PreviewUi.sw.Stop(); 27 | Program.mainForm.SetProgress(100f); 28 | inputCutoutPath = Path.Combine(Paths.previewPath, "preview.png.png"); 29 | outputCutoutPath = Directory.GetFiles(Paths.previewOutPath, "preview.*", SearchOption.AllDirectories)[0]; 30 | 31 | Image sourceImg = ImgUtils.GetImage(Paths.tempImgPath); 32 | float scale = GetScale(); 33 | 34 | if (sourceImg.Width * scale > 16000 || sourceImg.Height * scale > 16000) 35 | { 36 | MergeOnlyCutout(); 37 | Program.ShowMessage("The scaled output image is very large (>16000px), so only the cutout will be shown.", "Warning"); 38 | return; 39 | } 40 | 41 | MergeScrollable(); 42 | } 43 | 44 | static void MergeScrollable() 45 | { 46 | 47 | if (offsetX < 0f) offsetX *= -1f; 48 | if (offsetY < 0f) offsetY *= -1f; 49 | float scale = GetScale(); 50 | offsetX *= scale; 51 | offsetY *= scale; 52 | Logger.Log("[Merger] Merging " + Path.GetFileName(outputCutoutPath) + " onto original using offset " + offsetX + "x" + offsetY); 53 | Image image = MergeInMemory(scale); 54 | PreviewUi.currentOriginal = ImgUtils.GetImage(Paths.tempImgPath); 55 | PreviewUi.currentOutput = image; 56 | PreviewUi.currentScale = ImgUtils.GetScaleFloat(ImgUtils.GetImage(inputCutoutPath), ImgUtils.GetImage(outputCutoutPath)); 57 | UiHelpers.ReplaceImageAtSameScale(PreviewUi.previewImg, image); 58 | Program.mainForm.SetProgress(0f, "Done."); 59 | } 60 | 61 | 62 | public static Image MergeInMemory(float scale) 63 | { 64 | Image scaledSourceImg; 65 | int oldWidth; 66 | int newWidth; 67 | 68 | if (!(ImageProcessing.preScaleMode == Upscale.ScaleMode.Percent && ImageProcessing.preScaleValue == 100)) 69 | { 70 | string tempScaledSourceImagePath = Path.Combine(Paths.tempImgPath.GetParentDir(), "scaled-source.png"); 71 | MagickImage scaledSourceMagickImg = new MagickImage(Paths.tempImgPath); 72 | oldWidth = scaledSourceMagickImg.Width; 73 | scaledSourceMagickImg = ImageProcessing.ResizeImagePre(scaledSourceMagickImg); 74 | newWidth = scaledSourceMagickImg.Width; 75 | scaledSourceMagickImg.Write(tempScaledSourceImagePath); 76 | scaledSourceImg = ImgUtils.GetImage(tempScaledSourceImagePath); 77 | } 78 | else 79 | { 80 | scaledSourceImg = ImgUtils.GetImage(Paths.tempImgPath); 81 | oldWidth = scaledSourceImg.Width; 82 | newWidth = scaledSourceImg.Width; 83 | } 84 | 85 | float preScale = (float)oldWidth / (float)newWidth; 86 | Image cutout = ImgUtils.GetImage(outputCutoutPath); 87 | 88 | int scaledWidth = (scaledSourceImg.Width * scale).RoundToInt(); 89 | int scaledHeight = (scaledSourceImg.Height * scale).RoundToInt(); 90 | 91 | if (scaledWidth == cutout.Width && scaledHeight == cutout.Height) 92 | { 93 | Logger.Log("[Merger] Cutout is the entire image - skipping merge"); 94 | return cutout; 95 | } 96 | 97 | var destImage = new Bitmap(scaledWidth, scaledHeight); 98 | 99 | using (var gfx = Graphics.FromImage(destImage)) 100 | { 101 | gfx.CompositingMode = CompositingMode.SourceCopy; 102 | gfx.CompositingQuality = CompositingQuality.HighQuality; 103 | gfx.InterpolationMode = (Program.currentFilter == FilterType.Point) ? InterpolationMode.NearestNeighbor : InterpolationMode.HighQualityBicubic; 104 | gfx.SmoothingMode = SmoothingMode.HighQuality; 105 | gfx.PixelOffsetMode = PixelOffsetMode.HighQuality; 106 | gfx.DrawImage(scaledSourceImg, 0, 0, destImage.Width, destImage.Height); // Scale up 107 | gfx.DrawImage(cutout, (offsetX / preScale).RoundToInt(), (offsetY / preScale).RoundToInt()); // Overlay cutout 108 | } 109 | 110 | return destImage; 111 | } 112 | 113 | static void MergeOnlyCutout() 114 | { 115 | float scale = GetScale(); 116 | 117 | MagickImage originalCutout = ImgUtils.GetMagickImage(inputCutoutPath); 118 | originalCutout.FilterType = Program.currentFilter; 119 | originalCutout.Resize(new Percentage(scale * 100)); 120 | string scaledCutoutPath = Path.Combine(Paths.previewOutPath, "preview-input-scaled.png"); 121 | originalCutout.Format = MagickFormat.Png; 122 | originalCutout.Quality = 0; // Save preview as uncompressed PNG for max speed 123 | originalCutout.Write(scaledCutoutPath); 124 | 125 | PreviewUi.currentOriginal = ImgUtils.GetImage(scaledCutoutPath); 126 | PreviewUi.currentOutput = ImgUtils.GetImage(outputCutoutPath); 127 | 128 | PreviewUi.previewImg.Image = PreviewUi.currentOutput; 129 | PreviewUi.previewImg.ZoomToFit(); 130 | PreviewUi.previewImg.Zoom = (int)Math.Round(PreviewUi.previewImg.Zoom * 1.01f); 131 | Program.mainForm.resetImageOnMove = true; 132 | Program.mainForm.SetProgress(0f, "Done."); 133 | } 134 | 135 | private static float GetScale() 136 | { 137 | MagickImage val = ImgUtils.GetMagickImage(inputCutoutPath); 138 | MagickImage val2 = ImgUtils.GetMagickImage(outputCutoutPath); 139 | float result = (float)val2.Width / (float)val.Width; 140 | return result; 141 | } 142 | 143 | public static void ShowOutput() 144 | { 145 | if (PreviewUi.currentOutput != null) 146 | { 147 | showingOriginal = false; 148 | UiHelpers.ReplaceImageAtSameScale(PreviewUi.previewImg, PreviewUi.currentOutput); 149 | } 150 | } 151 | 152 | public static void ShowOriginal() 153 | { 154 | if (PreviewUi.currentOriginal != null) 155 | { 156 | showingOriginal = true; 157 | UiHelpers.ReplaceImageAtSameScale(PreviewUi.previewImg, PreviewUi.currentOriginal); 158 | } 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /Code/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Runtime.Versioning; 6 | 7 | [assembly: CompilationRelaxations(8)] 8 | [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] 9 | [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] 10 | [assembly: AssemblyTitle("Cupscale")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Cupscale")] 15 | [assembly: AssemblyCopyright("Copyright © 2020")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: ComVisible(false)] 18 | [assembly: Guid("62e28ebf-af79-4e5e-ad05-b95dfa65b232")] 19 | [assembly: AssemblyFileVersion("1.0.0.0")] 20 | [assembly: AssemblyVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /Code/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Cupscale.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Code/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Code/Resources/7za.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/7za.exe -------------------------------------------------------------------------------- /Code/Resources/CupscaleLogo1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/CupscaleLogo1.ico -------------------------------------------------------------------------------- /Code/Resources/baseline_fact_check_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/baseline_fact_check_white_48dp.png -------------------------------------------------------------------------------- /Code/Resources/baseline_folder_open_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/baseline_folder_open_white_48dp.png -------------------------------------------------------------------------------- /Code/Resources/baseline_photo_library_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/baseline_photo_library_white_48dp.png -------------------------------------------------------------------------------- /Code/Resources/baseline_refresh_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/baseline_refresh_white_48dp.png -------------------------------------------------------------------------------- /Code/Resources/baseline_settings_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/baseline_settings_white_48dp.png -------------------------------------------------------------------------------- /Code/Resources/discordIcoColored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/discordIcoColored.png -------------------------------------------------------------------------------- /Code/Resources/ffmpeg-h264.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/ffmpeg-h264.exe -------------------------------------------------------------------------------- /Code/Resources/interp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/interp.png -------------------------------------------------------------------------------- /Code/Resources/modelCompare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/modelCompare.png -------------------------------------------------------------------------------- /Code/Resources/patreon256pxColored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/patreon256pxColored.png -------------------------------------------------------------------------------- /Code/Resources/paypal256px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/paypal256px.png -------------------------------------------------------------------------------- /Code/Resources/questmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/Resources/questmark.png -------------------------------------------------------------------------------- /Code/Resources/shipped-files-version.txt: -------------------------------------------------------------------------------- 1 | 18 # fp16 support, removed esrgan-launcher 2 | 17 # no idea what changed but git said esrgan.7z changed 3 | 16 # fixed img writing again 4 | 15 # fixed img writing for joey's esrgan 5 | 14 # joey's esrgan update, auto-tiling 6 | 13 # new h265 supporting ffmpeg exe 7 | 12 # joey's esrgan update, fix chaining 8 | 11 # added joey's esrgan to fix seams with esrl code 9 | 10 # added interp py script 10 | 9 # fixed esrl output path 11 | 8 # updated scripts to not log filename for error handling 12 | 7 # updated joey's esrgan code to commit 6b58c546938e3563e5c0419e4d6468e78e3736d7 13 | 6 # fixed esrgan-launcher buffer writing 14 | 5 # updated esrgan scripts to write image buffer to tmp file 15 | 4 # updated esrgan scripts 16 | 3 # updated esrlmain.py to fix chaining problem 17 | 2 # added joey's esrgan 18 | 1 # added ffmpeg -------------------------------------------------------------------------------- /Code/UI/Controls/ModelCombox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | 9 | namespace System.Windows.Forms 10 | { 11 | class ModelCombox : ComboBox 12 | { 13 | 14 | //bool initialized = false; 15 | 16 | public ModelCombox () // Constructor 17 | { 18 | base.Text = "Open the dropdown to select a model."; 19 | } 20 | 21 | /* 22 | protected override void OnVisibleChanged(EventArgs e) 23 | { 24 | 25 | if (!IsRunning()) 26 | return; 27 | base.Text = "running"; 28 | 29 | base.OnVisibleChanged(e); 30 | 31 | if (!initialized) 32 | { 33 | UIHelpers.FillModelComboBox(this, false); 34 | initialized = true; 35 | } 36 | 37 | } 38 | */ 39 | 40 | protected override void OnDropDown(EventArgs e) 41 | { 42 | // if (!IsRunning()) 43 | // return; 44 | base.OnDropDown(e); 45 | Cupscale.UiHelpers.FillModelComboBox(this, false); 46 | } 47 | 48 | /* 49 | bool IsRunning() 50 | { 51 | return LicenseManager.UsageMode == LicenseUsageMode.Runtime; 52 | } 53 | */ 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Code/UI/DialogQueue.cs: -------------------------------------------------------------------------------- 1 | using Cupscale.Forms; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection.Emit; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Cupscale.UI 10 | { 11 | class DialogQueue 12 | { 13 | static bool running = false; 14 | public static Queue queue = new Queue(); 15 | 16 | public static void Init () 17 | { 18 | if(!running) 19 | ShowQueue(); 20 | } 21 | 22 | static async Task ShowQueue () 23 | { 24 | running = true; 25 | while (true) 26 | { 27 | if (queue.Count > 0) 28 | { 29 | MsgBox currentDialog = queue.Peek(); 30 | //Logger.Log("Showing msg - " + ) 31 | Program.mainForm.Activate(); 32 | currentDialog.ShowDialog(); 33 | currentDialog.BringToFront(); 34 | await Task.Delay(100); 35 | } 36 | await Task.Delay(1); 37 | } 38 | } 39 | 40 | public static void CloseCurrent () 41 | { 42 | if (queue.Count <= 0) 43 | return; 44 | MsgBox currentDialog = queue.Dequeue(); 45 | currentDialog.Close(); 46 | } 47 | 48 | public static void ShowDialog (MsgBox form) 49 | { 50 | queue.Enqueue(form); 51 | } 52 | 53 | public static bool IsOpen (MsgBox form) 54 | { 55 | return queue.Contains(form); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Code/UI/ExtensionMethods.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Code/UI/ExtensionMethods.cs -------------------------------------------------------------------------------- /Code/UI/ModelComparisonTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Cupscale.UI 8 | { 9 | class ModelComparisonTool 10 | { 11 | public static string lastCompositionModels; 12 | 13 | public static int cropModeComboxIndex = -1; 14 | public static int compositionModeComboxIndex = -1; 15 | public static int comparisonModeComboxIndex = -1; 16 | public static int scaleComboxIndex = -1; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Code/UI/UIHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Windows.Forms; 7 | using Cupscale.Main; 8 | using Cupscale.UI; 9 | using Cyotek.Windows.Forms; 10 | 11 | namespace Cupscale 12 | { 13 | internal class UiHelpers 14 | { 15 | public static void InitCombox(ComboBox box, int index) 16 | { 17 | if (box.Items.Count >= 1) 18 | { 19 | box.SelectedIndex = index; 20 | box.Text = box.Items[index].ToString(); 21 | } 22 | } 23 | 24 | public static void FillModelComboBox(ComboBox box, bool resetIndex = false) 25 | { 26 | EsrganData.ReloadModelList(); 27 | box.Items.Clear(); 28 | foreach (string model in EsrganData.models) 29 | { 30 | box.Items.Add(model); 31 | } 32 | if (resetIndex || string.IsNullOrEmpty(box.Text)) 33 | { 34 | InitCombox(box, 0); 35 | } 36 | } 37 | 38 | public static void FillComboBoxWithList(ComboBox box, Type type, int defaultIndex = 0) 39 | { 40 | box.Items.Clear(); 41 | 42 | foreach (string item in Enum.GetNames(type)) 43 | box.Items.Add(item.TitleCase()); 44 | 45 | InitCombox(box, defaultIndex); 46 | } 47 | 48 | public static void FillComboBoxWithList(ComboBox box, List list, int defaultIndex = 0) 49 | { 50 | box.Items.Clear(); 51 | 52 | foreach (string item in list) 53 | box.Items.Add(item); 54 | 55 | InitCombox(box, defaultIndex); 56 | } 57 | 58 | public static void ReplaceImageAtSameScale(ImageBox imgBox, Image newImg) 59 | { 60 | //Logger.Log("Replacing image on " + imgBox.Name + " with new image (" + newImg.Width + "x" + newImg.Height + ")"); 61 | float num = (float)imgBox.Image.Width / (float)newImg.Width; 62 | float num2 = (float)imgBox.AutoScrollPosition.X / num; 63 | float num3 = (float)imgBox.AutoScrollPosition.Y / num; 64 | if (num2 < 0f) 65 | { 66 | num2 *= -1f; 67 | } 68 | if (num3 < 0f) 69 | { 70 | num3 *= -1f; 71 | } 72 | num2 *= num; 73 | num3 *= num; 74 | imgBox.Image = newImg; 75 | imgBox.Zoom = (int)Math.Round((float)imgBox.Zoom * num); 76 | Point autoScrollPosition = imgBox.AutoScrollPosition; 77 | autoScrollPosition.X = (int)num2; 78 | autoScrollPosition.Y = (int)num3; 79 | imgBox.AutoScrollPosition = autoScrollPosition; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Code/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 53 | 54 | 55 | true 56 | 57 | 58 | 59 | 60 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Installer Files/av.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Installer Files/av.7z -------------------------------------------------------------------------------- /Installer Files/esrgan-ncnn.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Installer Files/esrgan-ncnn.7z -------------------------------------------------------------------------------- /Installer Files/esrgan.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Installer Files/esrgan.7z -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 N00MKRAD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Media/baseline_settings_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Media/baseline_settings_white_48dp.png -------------------------------------------------------------------------------- /Media/discordIcoColored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Media/discordIcoColored.png -------------------------------------------------------------------------------- /Media/patreon256pxColored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n00mkrad/cupscale/35d418c55c80c5426ebd2695c0396c7ad3cc7605/Media/patreon256pxColored.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cupscale 2 | Image Upscaling GUI based on ESRGAN 3 | 4 | ![](https://i.imgur.com/ntIuSrv.png) 5 | 6 | ## Credits: 7 | 8 | Based around [xinntao's ESRGAN](https://github.com/xinntao/ESRGAN) implemented via [Joey's Fork](https://github.com/JoeyBallentine/ESRGAN). 9 | 10 | AMD/Intel GPU compatibility is possible thanks to BlueAmulet's [esrgan-ncnn-vulkan](https://github.com/BlueAmulet/realsr-ncnn-vulkan) based on nihui's [realsr-ncnn-vulkan](https://github.com/nihui/realsr-ncnn-vulkan) running on Tencent's [ncnn](https://github.com/Tencent/ncnn) framework, as well as [xinntao's Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN). 11 | 12 | ## Download: 13 | 14 | [Get the latest release](https://github.com/n00mkrad/cupscale/releases) 15 | 16 | ## Installation: 17 | 18 | The application is more or less portable. It's a single executable that you can run anywhere. 19 | 20 | Temporary files are stored in the installation directory by default, which is why you shouldn't install the application in protected locations like Program Files. 21 | 22 | ## Supported AI Backends: 23 | 24 | - Nvidia CUDA (Recommended) 25 | - Vulkan (Works on any modern GPU, but is slower and takes a long time start up) 26 | - CPU (Works without GPU, but is very slow) 27 | 28 | ## Features: 29 | 30 | - CUDA, Vulkan/NCNN or CPU supported, with included model converter for NCNN 31 | - On-the-fly Model Interpolation 32 | - Model Chaining (Run images through multiple models at once) 33 | - Batch Upscaling (Load a directory or multiple single images) 34 | - Automatic Image tiling/merging to avoid running out of VRAM 35 | - Pre-Processing: Optionally downscale images before upscaling 36 | - Post-Processing: Automatically resize after upscaling 37 | - Compatible with PNG, JPEG, BMP, WEBP, TGA, DDS images 38 | - Load image straight out of the clipboard (no need to download images from web) 39 | - Create various types of comparisons (Side-By-Side, 50/50, and before/after animations as GIF or MP4) 40 | --------------------------------------------------------------------------------