diff --git a/bin/__pycache__/handler.cpython-311.pyc b/bin/__pycache__/handler.cpython-311.pyc index 97e96ea..5073f74 100644 Binary files a/bin/__pycache__/handler.cpython-311.pyc and b/bin/__pycache__/handler.cpython-311.pyc differ diff --git a/bin/engines/fsr/config.json b/bin/engines/fsr/config.json new file mode 100644 index 0000000..6ed207b --- /dev/null +++ b/bin/engines/fsr/config.json @@ -0,0 +1,15 @@ +{ + "abbr":"FSR", + "displayName":"FidelityFX_CLI", + "lastUsedFilePath":"sc", + "fileNameBeginning":"ig", + "cliModeOptions": { + "fsr":{ "displayName": "FidelityFX Super Resolution", "default": true }, + "c":{ "displayName": "Cubic", "default": false }, + "hqc":{ "displayName": "High Quality Cubic", "default": false } + }, + "pluginCreator": "Janis Hutz", + "pluginCreatorLink": "https://janishutz.com", + "engineLink": "", + "supports": [ "upscaling", "sharpening" ] +} \ No newline at end of file diff --git a/bin/engines/fsr.py b/bin/engines/fsr/fsr.py similarity index 83% rename from bin/engines/fsr.py rename to bin/engines/fsr/fsr.py index b55c1b7..c18f648 100644 --- a/bin/engines/fsr.py +++ b/bin/engines/fsr/fsr.py @@ -4,21 +4,37 @@ import time import subprocess import sys -class FSRScaler: - def __init__(self): +class Scaler: + def __init__( self ): self.os_type = sys.platform - self.command = "" - self.tmppath = "" + self.command = '' + self.tmppath = '' self.videometa = {} - def fsrScaler ( self, tmppath, filepath, threads, fsrpath, quality_setting, sharpening, scaling, filetype, mode ): + def singleScaler ( self, input_path, output_path, scalefactor, threads, mode ): + if self.os_type == 'linux': + self.command = f'wine ./bin/lib/FidelityFX_CLI.exe -Mode { mode } -Scale {scalefactor} {scalefactor} {input_path} {output_path}' + elif self.os_type == 'win32': + self.command = f'FidelityFX_CLI -Mode { mode } -Scale {scalefactor} {scalefactor} {input_path} {output_path}' + else: + print( 'OS CURRENTLY UNSUPPORTED!' ) + return False + + os.system( self.command ) + print( '\n\n==>Photo upscaled' ); + + def videoScaler ( self, tmppath, threads, scalefactor, sharpening, filetype, mode ): + self.isScaling = True + if ( scalefactor == 0 or scalefactor == None ): + self.isScaling = False + # Locate Images and assemble FSR-Command self.file_list = [] - self.filelist = os.listdir(tmppath) + self.filelist = os.listdir( tmppath ) self.filelist.pop(0) self.filelist.sort() self.number = 0 - if sharpening != '' and sharpening != None: + if sharpening != 0 and sharpening != None: for self.file in self.filelist: self.number += 1 if ( self.os_type == 'win32' ): @@ -57,10 +73,10 @@ class FSRScaler: if ( threads > multiprocessing.cpu_count() ): self.threads = multiprocessing.cpu_count(); - if ( not scaling ): + if ( self.isScaling ): engines = { 'c': 'Cubic', 'hqc': 'High Quality Cubic', 'fsr':'FidelityFX Super Resolution' } print( f'\n\n==> Upscaling using { self.threads } threads <==\n\n' ); - print( f'\n\n==> Upscaling Engine is { engines[ mode.lower() ] } <==\n\n' ); + print( f'\n\n==> Upscaling Engine is FidelityFX_CLI with algorithm { engines[ mode.lower() ] } <==\n\n' ); time.sleep( 2 ); @@ -74,20 +90,20 @@ class FSRScaler: if ( i == self.threads - 1 ): for element in self.file_list: self.files += element; - self.command_list.append( ( self.files, fsrpath, quality_setting, i, self.maxlength, self.os_type, mode ) ) + self.command_list.append( ( self.files, scalefactor, i, self.maxlength, self.os_type, mode ) ) self.pool = multiprocessing.Pool( self.threads ) self.pool.starmap( upscalerEngine, self.command_list ); self.pool.close(); self.pool.join(); - if sharpening != '' and sharpening != None: + if sharpening != 0 and sharpening != None: print( f'\n\n\n==> Sharpening using { self.threads } threads <==\n\n' ); time.sleep( 2 ); self.pathSharpening = tmppath - if ( not scaling ): + if ( self.isScaling ): if ( self.os_type == 'win32' ): self.pathSharpening += 'up\\' elif ( self.os_type == 'linux' ): @@ -128,7 +144,7 @@ class FSRScaler: if ( i == self.threads - 1 ): for element in self.file_list: self.files += element; - self.command_list.append( ( self.files, fsrpath, i, self.maxlength, self.os_type, sharpening, not sharpening ) ) + self.command_list.append( ( self.files, i, self.maxlength, self.os_type, sharpening, not sharpening ) ) self.pool = multiprocessing.Pool( self.threads ) self.pool.starmap( sharpeningEngine, self.command_list ); @@ -137,7 +153,7 @@ class FSRScaler: # Add return values -def upscalerEngine ( files, fsrpath, quality_setting, number, maxlength, os_type, version ): +def upscalerEngine ( files, scalefactor, number, maxlength, os_type, version ): scaler = 'FSR' if ( version.upper() == 'HQC' ): scaler = 'HighQualityCubic' @@ -191,9 +207,9 @@ def upscalerEngine ( files, fsrpath, quality_setting, number, maxlength, os_type while len( fileout ) > 0: files_handle = fileout.pop(0) if os_type == 'linux': - command_us = f'wine {fsrpath} -Mode { scaler } -Scale {quality_setting} {quality_setting} {files_handle}' + command_us = f'wine ./bin/lib/FidelityFX_CLI.exe -Mode { scaler } -Scale {scalefactor}x {scalefactor}x {files_handle}' elif os_type == 'win32': - command_us = f'FidelityFX_CLI -Mode { scaler } -Scale {quality_setting} {quality_setting} {files_handle}' + command_us = f'FidelityFX_CLI -Mode { scaler } -Scale {scalefactor}x {scalefactor}x {files_handle}' else: print( 'OS CURRENTLY UNSUPPORTED!' ) return False @@ -209,7 +225,7 @@ def upscalerEngine ( files, fsrpath, quality_setting, number, maxlength, os_type # ####################### -def sharpeningEngine ( files, fsrpath, number, maxlength, os_type, sharpening, didUpscale ): +def sharpeningEngine ( files, number, maxlength, os_type, sharpening, didUpscale ): files = files; # Refactoring of commands that are longer than 32K characters fileout = []; @@ -265,7 +281,7 @@ def sharpeningEngine ( files, fsrpath, number, maxlength, os_type, sharpening, d files_handle = fileout.pop(0) print( '\n\n\n PROCESS: ', number, '\nRunning sharpening filter\n\n\n' ); if os_type == 'linux': - command_sharpening = f'wine {fsrpath} -Mode CAS -Sharpness {sharpening} {files_handle}' + command_sharpening = f'wine ./bin/lib/FidelityFX_CLI.exe -Mode CAS -Sharpness {sharpening} {files_handle}' elif os_type == 'win32': command_sharpening = f'FidelityFX_CLI -Mode CAS -Sharpness {sharpening} {files_handle}' else: diff --git a/bin/engines/ss.py b/bin/engines/ss.py deleted file mode 100644 index ad767d1..0000000 --- a/bin/engines/ss.py +++ /dev/null @@ -1,90 +0,0 @@ -import os -import subprocess -import multiprocessing -import time -import sys - -class SpecialScaler: - def __init__(self): - self.os_type = sys.platform - self.command = "" - self.tmppath = "" - self.videometa = {} - - def superScaler ( self, tmppath, threads, quality_setting, os_platform, model ): - print( '\n\n==> Preparing to upscale videos <==\n\n==> You will see a lot of numbers flying by showing the progress of the upscaling of each individual image.\n==> This process might take a long time, depending on the length of the video.\n\n') - time.sleep( 2 ); - - try: - os.mkdir( f'{tmppath}sc' ) - except FileExistsError: - pass - if ( os_platform == 'win32' ): - self.command = f'realesrgan-ncnn-vulkan -i {tmppath} -o {tmppath}sc -s {quality_setting} -j {threads}:{threads}:{threads} -n {model}' - elif ( os_platform == 'linux' ): - self.command = f'wine ./bin/lib/realesrgan-ncnn-vulkan.exe -i {tmppath} -o {tmppath}sc -s {quality_setting} -j {threads}:{threads}:{threads} -n {model}' - os.system( self.command ); - - - def specialSuperScaler ( self, tmppath, threads, quality_setting, model ): - self.fileList = os.listdir( tmppath ) - self.fileList.pop( 0 ) - self.fileList.sort() - if ( threads > multiprocessing.cpu_count() * 2 ): - self.threads = multiprocessing.cpu_count() * 2; - else: - self.threads = threads - - self.fileCount = len( self.fileList ) // self.threads - self.spareFiles = len( self.fileList ) % self.threads - - self.cmdList = []; - - for t in range( threads ): - try: - os.mkdir( f'{tmppath}{t}' ) - except FileExistsError: - pass - - self.base = t * self.fileCount; - if ( self.os_type == 'win32' ): - for j in range( self.fileCount ): - os.rename( f'{tmppath}{self.fileList[ self.base + j ] }', f'{tmppath}{ t }\\{self.fileList[ self.base + j ] }' ) - elif ( self.os_type == 'linux' ): - for j in range( self.fileCount ): - os.rename( f'{tmppath}{self.fileList[ self.base + j ] }', f'{tmppath}{ t }/{self.fileList[ self.base + j ] }' ) - - self.cmdList.append( ( tmppath, t, quality_setting, model, self.os_type ) ) - - try: - os.mkdir( f'{tmppath}{self.threads + 1}' ) - except FileExistsError: - pass - - if ( self.os_type == 'win32' ): - for k in range( self.spareFiles ): - os.rename( f'{tmppath}{self.fileList[ self.threads * self.fileCount + k ] }', f'{tmppath}{ t }\\{self.fileList[ self.threads * self.fileCount + k ] }' ) - elif ( self.os_type == 'linux' ): - for k in range( self.spareFiles ): - os.rename( f'{tmppath}{self.fileList[ self.threads * self.fileCount + k ] }', f'{tmppath}{ self.threads + 1 }/{self.fileList[ self.threads * self.fileCount + k ] }' ) - - try: - os.mkdir( f'{tmppath}sc' ) - except FileExistsError: - pass - - self.pool_ss = multiprocessing.Pool( self.threads ) - self.pool_ss.starmap( specialScalerEngine, self.cmdList ); - self.pool_ss.close(); - self.pool_ss.join(); - - specialScalerEngine( tmppath, t, quality_setting, model, self.os_type ) - - -def specialScalerEngine ( tmppath, tNumber, quality_setting, model, os_type ): - if ( os_type == 'win32' ): - command = f'realesrgan-ncnn-vulkan -i {tmppath}{tNumber} -o {tmppath}sc -s {quality_setting} -n {model}' - elif ( os_type == 'linux' ): - command = f'wine ./bin/lib/realesrgan-ncnn-vulkan.exe -i {tmppath}{tNumber} -o {tmppath}sc -s {quality_setting} -n {model}' - sub = subprocess.Popen( command, shell=True ); - sub.wait(); \ No newline at end of file diff --git a/bin/engines/ss/config.json b/bin/engines/ss/config.json new file mode 100644 index 0000000..5564f49 --- /dev/null +++ b/bin/engines/ss/config.json @@ -0,0 +1,14 @@ +{ + "abbr":"SS", + "displayName":"Real-ESGRAN", + "lastUsedFilePath":"sc", + "fileNameBeginning":"ig", + "cliModeOptions": { + "av3":{ "displayName": "realesr-animevideov3", "default": true }, + "x4plus":{ "displayName": "realesrgan-x4plus-anime", "default": false } + }, + "pluginCreator": "Janis Hutz", + "pluginCreatorLink": "https://janishutz.com", + "engineLink": "", + "supports": [ "upscaling" ] +} \ No newline at end of file diff --git a/bin/engines/ss/ss.py b/bin/engines/ss/ss.py new file mode 100644 index 0000000..b90963e --- /dev/null +++ b/bin/engines/ss/ss.py @@ -0,0 +1,38 @@ +import os +import subprocess +import multiprocessing +import time +import sys + +class Scaler: + def __init__(self): + self.os_type = sys.platform + self.command = "" + self.tmppath = "" + self.videometa = {} + + def singleScaler ( self, input_path, output_path, scalefactor, threads, mode ): + if self.os_type == 'linux': + self.command = f'wine ./bin/lib/FidelityFX_CLI.exe -Scale {scalefactor} {scalefactor} {input_path} {output_path} -n { mode }' + elif self.os_type == 'win32': + self.command = f'realesrgan-ncnn-vulkan -i {input_path} -o {output_path} -s {scalefactor} -j {threads}:{threads}:{threads} -n { mode }' + else: + print( 'OS CURRENTLY UNSUPPORTED!' ) + return False + + os.system( self.command ) + print( '\n\n==>Photo upscaled' ); + + def videoScaler ( self, tmppath, threads, scalefactor, sharpening, filetype, mode ): + print( '\n\n==> Preparing to upscale videos <==\n\n==> You will see a lot of numbers flying by showing the progress of the upscaling of each individual image.\n==> This process might take a long time, depending on the length of the video.\n\n') + time.sleep( 2 ); + + try: + os.mkdir( f'{tmppath}sc' ) + except FileExistsError: + pass + if ( self.os_type == 'win32' ): + self.command = f'realesrgan-ncnn-vulkan -i {tmppath} -o {tmppath}sc -s {scalefactor} -j {threads}:{threads}:{threads} -n {mode}' + elif ( self.os_type == 'linux' ): + self.command = f'wine ./bin/lib/realesrgan-ncnn-vulkan.exe -i {tmppath} -o {tmppath}sc -s {scalefactor} -j {threads}:{threads}:{threads} -n {mode}' + os.system( self.command ); \ No newline at end of file diff --git a/bin/handler.py b/bin/handler.py index 10eacbc..487520c 100644 --- a/bin/handler.py +++ b/bin/handler.py @@ -1,11 +1,11 @@ -""" +''' * FSRImageVideoUpscalerFrontend - handler.py * * Created by Janis Hutz 03/14/2023, Licensed under the GPL V3 License * https://janishutz.com, development@janishutz.com * * -""" +''' import os @@ -15,12 +15,14 @@ ffmpeg = bin.probe import configparser import time import shutil -import bin.engines.ss -import bin.engines.fsr +import importlib -fsr = bin.engines.fsr.FSRScaler() -ss = bin.engines.ss.SpecialScaler() +importedModules = {} +engineList = os.listdir( 'bin/engines' ); +engineList.pop( 0 ) +for element in engineList: + importedModules[ element ] = importlib.import_module( 'bin.engines.' + element + '.' + element ).Scaler() # Loading the config file to get user preferred temp path config = configparser.ConfigParser() @@ -30,64 +32,56 @@ config.read('./config/settings.ini') class Handler: def __init__(self): self.os_type = sys.platform - self.command = "" - self.tmppath = "" + self.command = '' + self.tmppath = '' self.videometa = {} # TODO: CHECK if this upscaler is any good: https://github.com/Maximellerbach/Image-Processing-using-AI (looks quite promising) - def handler(self, fsrpath, filepath, quality_setting, output_path, sharpening, scaling, filetype, scalerEngine, model, useSpecialModeSS, threads=4 ): + def handler( self, filepath, scalefactor, output_path, sharpening, filetype, engine, mode, threads=4 ): # Function to be called when using this class as this function automatically determines if file is video or image - print( '\n\nFSRImageVideoUpscalerFrontend - V1.1.0\n\nCopyright 2023 FSRImageVideoUpscalerFrontend contributors\n\n\n\n' ); + print( '\n\n ImageVideoUpscaler - V1.1.0\n\n(c) 2023 ImageVideoUpscaler contributors\n\n\n\n' ); - if self.os_type == "linux": - self.tmppath = config["PathSettings"]["tmpPathLinux"] - elif self.os_type == "win32": - self.tmppath = config["PathSettings"]["tmpPathWindows"] + if self.os_type == 'linux': + self.tmppath = config['PathSettings']['tmpPathLinux'] + elif self.os_type == 'win32': + self.tmppath = config['PathSettings']['tmpPathWindows'] else: - print("OS CURRENTLY UNSUPPORTED!") + print('OS CURRENTLY UNSUPPORTED!') return False if ( self.os_type == 'win32' ): self.tmppath += '\\fsru\\' else: if ( self.tmppath[len(self.tmppath) - 1: ] == '/' ): - self.tmppath += "fsru/" + self.tmppath += 'fsru/' else: self.tmppath += '/fsru/' + # checking for spaces in filepath (for use with terminal commands) - self.filepath = "" + self.filepath = '' for self.letter in filepath: - if self.letter == " ": - self.filepath += "\ " + if self.letter == ' ': + self.filepath += '\ ' else: self.filepath += self.letter # Determining filetype - if str(filepath)[len(filepath) - 4:] == ".mp4" or str(filepath)[len(filepath) - 4:] == ".mkv" or str(filepath)[len(filepath) - 4:] == ".MP4": + if str(filepath)[len(filepath) - 4:] == '.mp4' or str(filepath)[len(filepath) - 4:] == '.mkv' or str(filepath)[len(filepath) - 4:] == '.MP4': print( '\n\n==> Upscaling video' ) - self.video_scaling( fsrpath, filepath, quality_setting, output_path, threads, sharpening, scaling, filetype, scalerEngine, model, useSpecialModeSS ) - elif str(filepath)[len(filepath) - 4:] == ".JPG" or str(filepath)[len(filepath) - 4:] == ".png" or str(filepath)[len(filepath) - 4:] == ".jpg" or str(filepath)[len(filepath) - 5:] == ".jpeg": + self.video_scaling( filepath, output_path, scalefactor, threads, sharpening, filetype, mode, engine ) + elif str(filepath)[len(filepath) - 4:] == '.JPG' or str(filepath)[len(filepath) - 4:] == '.png' or str(filepath)[len(filepath) - 4:] == '.jpg' or str(filepath)[len(filepath) - 5:] == '.jpeg': print( '\n==>upscaling image' ) - self.photo_scaling(fsrpath, filepath, quality_setting, output_path) + self.photo_scaling( scalefactor, output_path, engine ) else: - print("not supported") + print('not supported') return False - def photo_scaling(self, fsrpath, filepath, quality_setting, output_path): + def photo_scaling(self, scalefactor, output_path, engine, mode): # DO NOT CALL THIS! Use Handler().handler() instead! - if self.os_type == "linux": - self.command = f"wine {fsrpath} -Scale {quality_setting} {quality_setting} {self.filepath} {output_path}" - elif self.os_type == "win32": - self.command = f"FidelityFX_CLI -Scale {quality_setting} {quality_setting} {self.filepath} {output_path}" - else: - print("OS CURRENTLY UNSUPPORTED!") - return False - - os.system(self.command) - print( '\n\n==>Photo upscaled' ); + pass - def video_scaling( self, fsrpath, filepath, quality_setting, output_path, threads, sharpening, scaling, filetype, scalerEngine, model, useSpecialModeSS ): + def video_scaling( self, input_path, output_path, scalefactor, threads, sharpening, filetype, mode, engine ): # DO NOT CALL THIS! Use Handler().handler() instead! # Splitting video into frames @@ -103,12 +97,12 @@ class Handler: print( '\n==> Created directory' ) - if self.os_type == "linux": - self.command = f"ffmpeg -i {str(self.filepath)} {self.tmppath}ig%08d.{ filetype }" - elif self.os_type == "win32": - self.command = f"ffmpeg -i {str(self.filepath)} \"{self.tmppath}ig%08d.{ filetype }\"" + if self.os_type == 'linux': + self.command = f'ffmpeg -i {str(self.filepath)} {self.tmppath}ig%08d.{ filetype }' + elif self.os_type == 'win32': + self.command = f'ffmpeg -i {str(self.filepath)} \"{self.tmppath}ig%08d.{ filetype }\"' else: - print("OS CURRENTLY UNSUPPORTED!") + print('OS CURRENTLY UNSUPPORTED!') return False os.system( self.command ) @@ -116,7 +110,7 @@ class Handler: # Retrieving Video metadata self.filelist = os.listdir(self.tmppath) - self.videometa = ffmpeg.probe(str(filepath))["streams"].pop(0) + self.videometa = ffmpeg.probe(str(input_path))['streams'].pop(0) self.duration = self.videometa.get( 'duration' ) self.frames = len( self.filelist ) @@ -134,17 +128,7 @@ class Handler: time.sleep( 2 ); - self.lastUsedPath = '' - - if ( scalerEngine.lower() == 'fsr' or scalerEngine.lower() == 'c' or scalerEngine.lower() == 'hqc' ): - self.lastUsedPath = fsr.fsrScaler( self.tmppath, filepath, threads, fsrpath, quality_setting + 'x', sharpening, scaling, filetype, scalerEngine ) - elif ( scalerEngine.upper() == 'SS' ): - if ( not useSpecialModeSS ): - self.lastUsedPath = ss.superScaler( self.tmppath, threads, quality_setting, self.os_type, model ) - else: - self.lastUsedPath = ss.specialSuperScaler( self.tmppath, threads, quality_setting, model ) - else: - raise Exception( 'ERROR upscaling. scalerEngine invalid' ); + importedModules[ engine ].videoScaler ( self.tmppath, int( threads ), int( scalefactor ), float( sharpening ), filetype, mode ) # get Video's audio print( '\n\n==>Finished Upscaling individual images. \n==>Retrieving Video audio to append\n\n' ) @@ -158,8 +142,8 @@ class Handler: time.sleep( 2 ); try: - os.remove(f"{self.tmppath}audio.aac") - os.remove(f"{output_path}") + os.remove(f'{self.tmppath}audio.aac') + os.remove(f'{output_path}') except FileNotFoundError: pass if self.os_type == 'linux': @@ -176,7 +160,7 @@ class Handler: if self.os_type == 'linux': self.command = f'ffmpeg -framerate {self.framerate} -i {self.tmppath}sc/ig%08d.{filetype} {output_path} -i {self.tmppath}audio.aac' elif self.os_type == 'win32': - self.command = f'ffmpeg -framerate {self.framerate} -i \"{self.tmppath}sc\\ig%08d.{filetype}\" {output_path} -i {self.tmppath}audio.aac' + self.command = f'ffmpeg -framerate {self.framerate} -i \'{self.tmppath}sc\\ig%08d.{filetype}\' {output_path} -i {self.tmppath}audio.aac' else: print( 'OS CURRENTLY UNSUPPORTED!' ); return False diff --git a/imagevideoupscaler-cli.py b/imagevideoupscaler-cli.py index ddff270..2377de4 100644 --- a/imagevideoupscaler-cli.py +++ b/imagevideoupscaler-cli.py @@ -11,97 +11,117 @@ import argparse import bin.handler import os import multiprocessing +import json + +engineList = os.listdir( 'bin/engines' ); +engineList.pop( 0 ) + +engineInfo = {} + +for engine in engineList: + engineInfo[ engine ] = json.load( open( 'bin/engines/' + engine + '/config.json' ) ) allowedFiletypes = [ 'png', 'jpg' ]; +def performChecks ( args, ap ): + if ( args.details == None or args.details == '' ): + if ( not args.printengines ): + # Check if input and output file arguments are available + if ( args.inputfile == None or args.inputfile == '' or args.outputfile == None or args.outputfile == '' ): + print( '\n\n ==> ERROR: Input and output file required! <==\n\n' ) + ap.print_usage(); + return False + + # check if output file exists and if, prompt user if it should be overwritten and remove if, if yes + if ( os.path.exists( args.outputfile ) ): + doReplace = input( '--> File already exists. Do you want to replace it? (Y/n) ' ).lower() + if ( doReplace == 'y' or doReplace == '' ): + os.remove( args.outputfile ); + else: + print( '\n==> Refusing to Upscale video. Please delete the file or specify another filepath! <==' ) + return False + + # check if engine argument is valid + try: + engineInfo[ args.engine ] + except KeyError: + print( '\n==> ERROR: Engine not available. Ensure you have specified a valid engine' ) + return False + + # Check scalefactor argument and also verify that engine supports upscaling + if ( int( args.scalefactor ) > 4 and int( args.scalefactor ) < -4 ): + print( '\n==> ERROR: Invalid scale factor. Value has to be an integer between -4 and 4' ) + return False + else: + if ( not 'upscaling' in engineInfo[ args.engine ][ 'supports' ] ): + print( '\n==> ERROR: This engine does NOT support upscaling' ) + return False + + # Check sharpening argument and also verify that engine supports it + if ( float( args.sharpening ) >= 1 and float( args.sharpening ) <= 0 ): + print( '\n==> ERROR: Invalid value for sharpening. Value has to be between 0 and 1' ) + return False + else: + if ( not 'sharpening' in engineInfo[ args.engine ][ 'supports' ] ): + print( '\n==> ERROR: This engine does NOT support sharpening' ) + return False + + # check if scalefactor and / or sharpening is available + if ( args.scalefactor == 0 and args.sharpening == 0 ): + print( '\n==> ERROR: Either scalefactor or sharpening argument required!' ) + return False + + # Check if filetype argument is valid + if ( not args.filetype in allowedFiletypes ): + print( '\n==> ERROR: Unknown filetype for temp files. Can be png or jpg' ) + return False + + # Check if mode of engine is valid + try: + engineInfo[ args.engine ][ 'cliModeOptions' ][ args.mode ] + except KeyError: + print( '\n==> ERROR: The specified mode is not supported by this engine. Options:' ) + for option in engineInfo[ args.engine ][ 'cliModeOptions' ]: + print( ' --> ' + engineInfo[ args.engine ][ 'cliModeOptions' ][ option ][ 'displayName' ] + ' (' + option + ')' ) + return False + + return True + else: + print( '\n\n==> Available engines <==\n' ) + for entry in engineList: + print( '--> ' + entry ) + print( '\n\n' ) + else: + print( '\n\n ==> INFOS about ' + engineInfo[ args.details ][ 'displayName' ] + '\n' ) + print( ' --> Engine cli option is: ' + engineInfo[ args.details ][ 'abbr' ].lower() ) + print( ' --> CLI mode options are: ' ) + for mode in engineInfo[ args.details ][ 'cliModeOptions' ]: + print( ' -> ' + engineInfo[ args.details ][ 'cliModeOptions' ][ mode ][ 'displayName' ] + ':' ) + print( ' > CLI name: ' + mode ) + print( ' > Is the default: ' + str( engineInfo[ args.details ][ 'cliModeOptions' ][ mode ][ 'default' ] ) ) + print( '\n\n' ) + if __name__ == '__main__': - ap = argparse.ArgumentParser( description='ImageVideoUpscaler - CLI, a CLI application to upscale videos and images using FSR.' ) - ap.add_argument( 'inputfile', help='File path for the video / image to be upscaled' ) - ap.add_argument( 'outputfile', help='File path for the video / image that was upscaled' ) - ap.add_argument( '-s', '--scalefactor', help='Scale factor for the video / image. Can be a integer from 1 - 4' ) - ap.add_argument( '-F', '--filetype', help='Change the file type of the temporary image files. Supports png, jpg. Video quality: png > jpg. PNG is default, if not specified.' ) + ap = argparse.ArgumentParser( description='ImageVideoUpscaler - CLI, a CLI application to upscale videos and images using different upscaling engines.' ) + ap.add_argument( '-i', '--inputfile', help='File path for the video / image to be upscaled' ) + ap.add_argument( '-o', '--outputfile', help='Output file path for the video / image that was upscaled' ) + ap.add_argument( '-s', '--scalefactor', help='Scale factor for the video / image. Can be a integer from -4 to 4' ) ap.add_argument( '-S', '--sharpening', help='Sharpening factor (between 0 and 1 whereas 0 means no sharpening, 1 the most sharpening. Recommendation: Do not exceed 0.25, as it often looks bad)' ) - ap.add_argument( '-t', '--threading', help='Use special threading mode with SS scaler (spawns 16 threads upscaling at one time)', action='store_true' ) ap.add_argument( '-T', '--threads', help='Thread count to use. Cannot exceed CPU thread count. Scaling non-linear (using 2 threads is not exactly 2x the speed of 1 thread). Scales well with FSR, barely with Real-ESRGAN, as it uses mostly the GPU to upscale' ) - ap.add_argument( '-E', '--engine', help='Upscaling engine. Can be fsr, C (for Cubic), HQC (for HighQuality Cubic) or SS (for Real-ESRGAN). FSR tends to be higher, Cubic is quite fast but quite low quality, HighQualityCubic is of higher quality, but slower. Real-ESRGAN is meant for anime and is super slow. Defaults to fsr' ) - ap.add_argument( '-M', '--model', help='Only available if using Real-ESRGAN. Change the ML-Model used to upsample video, can be: realesr-animevideov3 | realesrgan-x4plus-anime , defaults to realesr-animevideov3' ) - ap.add_argument( '-N', '--noscaling', help='Do not upscale video, instead only sharpen. Sharpening argument required!', action='store_true' ) + ap.add_argument( '-E', '--engine', help='Upscaling engine. By default can be fsr or ss. Use the -p option to see all installed engines' ) + ap.add_argument( '-M', '--mode', help='Specify a special mode for a specific engine. Might not be available in every engine. Use the -d option to find out more' ) + ap.add_argument( '-F', '--filetype', help='Change the file type of the temporary image files. Supports png, jpg. Video quality: png > jpg. PNG is default, if not specified.' ) + ap.add_argument( '-d', '--details', help='Get details on usage of a particular engine and exit. Reads the config.json file of that engine and displays it in a HR manner' ) + ap.add_argument( '-p', '--printengines', help='Print all engines and exit', action='store_true' ) + ap.set_defaults( scaling = 0, sharpening = 0, threads = 4, engine = 'fsr', mode = 'fsr', filetype = 'png' ) args = ap.parse_args() handler = bin.handler.Handler() - - go = True; - go2 = True; - go3 = True; - specialMode = False; - engine = 'fsr'; - model = 'realesr-animevideov3'; - availableModels = [ 'realesr-animevideov3', 'realesrgan-x4plus-anime' ]; - + multiprocessing.freeze_support(); - if ( os.path.exists( args.outputfile ) ): - doReplace = input( 'File already exists. Do you want to replace it? (Y/n) ' ).lower() - if ( doReplace == 'y' or doReplace == '' ): - go = True - os.remove( args.outputfile ); - else: - print( '\nRefusing to Upscale video. Please delete the file or specify another filepath!') - go = False - if ( args.engine != None ): - if ( args.engine == 'fsr' or args.engine == 'SS' or args.engine.lower() == 'c' or args.engine.lower() == 'hqc' ): - engine = args.engine; - else: - print( 'Invalid argument for engine' ) - go2 = False; - - if ( engine == 'SS' and args.model != None ): - if ( args.model in availableModels ): - model = args.model; - else: - print( 'Invalid argument for model. Can be: realesr-animevideov3 | realesrgan-x4plus-anime' ) - go2 = False; - - if ( args.noscaling ): - if ( args.sharpening != None ): - if ( float( args.sharpening ) > 0 ): - go2 = True; - else: - go2 = False; - else: - print( 'Missing argument for Sharpening. Please specify that argument and try again!' ) - go2 = False; - - if ( args.sharpening != None ): - if ( float( args.sharpening ) > 1 ): - print( 'Invalid argument for Sharpening, please specify a value between 0 and 1!' ) - go3 = False; - - if ( args.filetype != None ): - if ( args.filetype in allowedFiletypes ): - filetype = args.filetype - else: - go3 = False - print( 'Invalid filetype for temp images specified. Please ensure to only use png or jpg!' ); - else: - filetype = 'png' - - specialMode = args.threading; + if ( performChecks( args, ap ) ): + handler.handler( args.inputfile, args.scalefactor, args.outputfile, args.sharpening, args.filetype, args.engine, args.mode, args.threads ) + print( '\n\n---------------------------------------------------------------------------------\n\nDONE \n\n\n\nImageVideoUpscalerFrontend V1.1.0\n\nCopyright 2023 FSRImageVideoUpscalerFrontend contributors\nThis application comes with absolutely no warranty to the extent permitted by applicable law\n\n\n\nOutput was written to ' + args.outputfile + '\n\n\n' ) - if ( go and go2 and go3 ): - if ( args.scalefactor ): - if ( int( args.scalefactor ) ): - if ( args.threads != None ): - handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, args.scalefactor, args.outputfile, args.sharpening, args.noscaling, filetype, engine, model, specialMode, threads=int( args.threads ) ); - else: - handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, args.scalefactor, args.outputfile, args.sharpening, args.noscaling, filetype, engine, model, specialMode ); - else: - raise NameError( 'Argument Scale does require to be an integer!' ) - else: - if ( args.threads != None ): - handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, '2', args.outputfile, args.sharpening, args.noscaling, filetype, engine, model, specialMode, threads=int( args.threads ) ); - else: - handler.handler( 'bin/lib/FidelityFX_CLI.exe', args.inputfile, '2', args.outputfile, args.sharpening, args.noscaling, filetype, engine, model, specialMode ) - print( '\n\n---------------------------------------------------------------------------------\n\nDONE \n\n\n\nImageVideoUpscalerFrontend V1.1.0\n\nCopyright 2023 FSRImageVideoUpscalerFrontend contributors\nThis application comes with absolutely no warranty to the extent permitted by applicable law\n\n\n\nYour video was saved to ' + args.outputfile + '\n\n\n' ) -