diff --git a/main.py b/main.py index 4b70ac4..c388650 100644 --- a/main.py +++ b/main.py @@ -6,7 +6,7 @@ try: from loguru import logger except ImportError: - raise RuntimeError('Please, install loguru using pip') + raise RuntimeError("Please, install loguru using pip") from system import clear from system.lib import config, locale, refill_menu, menu @@ -29,14 +29,16 @@ def main(): start_time = time.time() with logger.catch(): handler() - logger.opt(colors=True).info(f'{locale.done % (time.time() - start_time)}') + logger.opt(colors=True).info( + f"{locale.done % (time.time() - start_time)}" + ) input(locale.to_continue) clear() -if __name__ == '__main__': +if __name__ == "__main__": try: main() except KeyboardInterrupt: - logger.info('Exit.') + logger.info("Exit.") pass diff --git a/system/__init__.py b/system/__init__.py index 077225e..9e263f9 100644 --- a/system/__init__.py +++ b/system/__init__.py @@ -3,24 +3,27 @@ from loguru import logger -is_windows = platform.system() == 'Windows' -null_output = f'{"nul" if is_windows else "/dev/null"} 2>&1' +is_windows = platform.system() == "Windows" +null_output = f"{'nul' if is_windows else '/dev/null'} 2>&1" def run(command: str, output_path: str = null_output): - return os.system(f'{command} > {output_path}') + return os.system(f"{command} > {output_path}") if is_windows: with logger.catch(): try: import colorama + colorama.init() except Exception as e: logger.exception(e) def clear(): - os.system('cls') + os.system("cls") + else: + def clear(): - os.system('clear') + os.system("clear") diff --git a/system/bytestream.py b/system/bytestream.py index b5e7160..6b94e60 100644 --- a/system/bytestream.py +++ b/system/bytestream.py @@ -3,7 +3,9 @@ class Reader(io.BytesIO): - def __init__(self, buffer: bytes = b'', endian: Literal['little', 'big'] = 'little'): + def __init__( + self, buffer: bytes = b"", endian: Literal["little", "big"] = "little" + ): super().__init__(buffer) self.buffer = buffer @@ -37,11 +39,11 @@ def read_string(self) -> str: length = self.read_uchar() if length != 255: return self.read(length).decode() - return '' + return "" class Writer(io.BytesIO): - def __init__(self, endian: Literal['little', 'big'] = 'little'): + def __init__(self, endian: Literal["little", "big"] = "little"): super().__init__() self.endian = endian diff --git a/system/lib/__init__.py b/system/lib/__init__.py index ce90432..d786e29 100644 --- a/system/lib/__init__.py +++ b/system/lib/__init__.py @@ -14,20 +14,20 @@ logger.remove() logger.add( - './logs/info/{time:YYYY-MM-DD}.log', - format='[{time:HH:mm:ss}] [{level}]: {message}', + "./logs/info/{time:YYYY-MM-DD}.log", + format="[{time:HH:mm:ss}] [{level}]: {message}", encoding="utf8", - level='INFO' + level="INFO", ) logger.add( - './logs/errors/{time:YYYY-MM-DD}.log', - format='[{time:HH:mm:ss}] [{level}]: {message}', + "./logs/errors/{time:YYYY-MM-DD}.log", + format="[{time:HH:mm:ss}] [{level}]: {message}", backtrace=True, diagnose=True, encoding="utf8", - level='ERROR' + level="ERROR", ) -logger.add(sys.stdout, format='[{level}] {message}', level='INFO') +logger.add(sys.stdout, format="[{level}] {message}", level="INFO") locale.load(config.language) @@ -36,6 +36,7 @@ try: # noinspection PyUnresolvedReferences import requests + del requests if config.auto_update and time.time() - config.last_update > 60 * 60 * 24 * 7: @@ -46,8 +47,8 @@ if config.has_update: logger.opt(colors=True).info(f'{locale.update_done % ""}') if Console.question(locale.done_qu): - latest_tag = get_tags('vorono4ka', 'xcoder')[0] - latest_tag_name = latest_tag['name'][1:] + latest_tag = get_tags("vorono4ka", "xcoder")[0] + latest_tag_name = latest_tag["name"][1:] config.has_update = False config.version = latest_tag_name @@ -66,6 +67,7 @@ def refill_menu(): try: import sc_compression + del sc_compression from system.lib.features.csv.compress import compress_csv @@ -73,6 +75,7 @@ def refill_menu(): try: import PIL + del PIL from system.lib.features.sc.decode import sc_decode @@ -81,87 +84,94 @@ def refill_menu(): from system.lib.features.sc.assembly_encode import sc1_encode sc_category = Menu.Category(0, locale.sc_label) - sc_category.add(Menu.Item( - locale.decode_sc, - locale.decode_sc_description, - sc_decode - )) - sc_category.add(Menu.Item( - locale.encode_sc, - locale.encode_sc_description, - sc_encode - )) - sc_category.add(Menu.Item( - locale.decode_by_parts, - locale.decode_by_parts_description, - decode_and_cut - )) - sc_category.add(Menu.Item( - locale.encode_by_parts, - locale.encode_by_parts_description, - sc1_encode - )) - sc_category.add(Menu.Item( - locale.overwrite_by_parts, - locale.overwrite_by_parts_description, - lambda: sc1_encode(True) - )) + sc_category.add( + Menu.Item(locale.decode_sc, locale.decode_sc_description, sc_decode) + ) + sc_category.add( + Menu.Item(locale.encode_sc, locale.encode_sc_description, sc_encode) + ) + sc_category.add( + Menu.Item( + locale.decode_by_parts, + locale.decode_by_parts_description, + decode_and_cut, + ) + ) + sc_category.add( + Menu.Item( + locale.encode_by_parts, + locale.encode_by_parts_description, + sc1_encode, + ) + ) + sc_category.add( + Menu.Item( + locale.overwrite_by_parts, + locale.overwrite_by_parts_description, + lambda: sc1_encode(True), + ) + ) menu.add_category(sc_category) except ImportError: - logger.warning(locale.install_to_unlock % 'PILLOW') + logger.warning(locale.install_to_unlock % "PILLOW") csv_category = Menu.Category(1, locale.csv_label) - csv_category.add(Menu.Item( - locale.decompress_csv, - locale.decompress_csv_description, - decompress_csv - )) - csv_category.add(Menu.Item( - locale.compress_csv, - locale.compress_csv_description, - compress_csv - )) + csv_category.add( + Menu.Item( + locale.decompress_csv, locale.decompress_csv_description, decompress_csv + ) + ) + csv_category.add( + Menu.Item( + locale.compress_csv, locale.compress_csv_description, compress_csv + ) + ) menu.add_category(csv_category) except ImportError: - logger.warning(locale.install_to_unlock % 'sc-compression') + logger.warning(locale.install_to_unlock % "sc-compression") other = Menu.Category(10, locale.other_features_label) try: import requests + del requests - other.add(Menu.Item( - locale.check_update, - locale.version % config.version, - check_update - )) + other.add( + Menu.Item( + locale.check_update, locale.version % config.version, check_update + ) + ) except ImportError: - logger.warning(locale.install_to_unlock % 'requests') - - other.add(Menu.Item( - locale.check_for_outdated, - None, - check_for_outdated - )) - other.add(Menu.Item( - locale.reinit, - locale.reinit_description, - lambda: (initialize(), refill_menu()) - )) - other.add(Menu.Item( - locale.change_language, - locale.change_lang_description % config.language, - lambda: (config.change_language(locale.change()), refill_menu()) - )) - other.add(Menu.Item( - locale.clear_directories, - locale.clean_dirs_description, - lambda: clear_directories() if Console.question(locale.clear_qu) else -1 - )) - other.add(Menu.Item( - locale.toggle_update_auto_checking, - locale.enabled if config.auto_update else locale.disabled, - lambda: (config.toggle_auto_update(), refill_menu()) - )) + logger.warning(locale.install_to_unlock % "requests") + + other.add(Menu.Item(locale.check_for_outdated, None, check_for_outdated)) + other.add( + Menu.Item( + locale.reinit, + locale.reinit_description, + lambda: (initialize(), refill_menu()), + ) + ) + other.add( + Menu.Item( + locale.change_language, + locale.change_lang_description % config.language, + lambda: (config.change_language(locale.change()), refill_menu()), + ) + ) + other.add( + Menu.Item( + locale.clear_directories, + locale.clean_dirs_description, + lambda: clear_directories() if Console.question(locale.clear_qu) else -1, + ) + ) + other.add( + Menu.Item( + locale.toggle_update_auto_checking, + locale.enabled if config.auto_update else locale.disabled, + lambda: (config.toggle_auto_update(), refill_menu()), + ) + ) other.add(Menu.Item(locale.exit, None, lambda: (clear(), exit()))) menu.add_category(other) diff --git a/system/lib/config.py b/system/lib/config.py index 09bba86..33fbf6b 100644 --- a/system/lib/config.py +++ b/system/lib/config.py @@ -3,19 +3,19 @@ class Config: - DEFAULT_LANGUAGE = 'en-EU' + DEFAULT_LANGUAGE = "en-EU" - config_path = './system/config.json' + config_path = "./system/config.json" inited: bool def __init__(self): self.config_items = ( - 'initialized', - 'version', - 'language', - 'has_update', - 'last_update', - 'auto_update', + "initialized", + "version", + "language", + "has_update", + "last_update", + "auto_update", ) self.initialized: bool = False @@ -41,10 +41,10 @@ def load(self): setattr(self, key, value) def dump(self): - json.dump({ - item: getattr(self, item) - for item in self.config_items - }, open(self.config_path, 'w')) + json.dump( + {item: getattr(self, item) for item in self.config_items}, + open(self.config_path, "w"), + ) config = Config() diff --git a/system/lib/console.py b/system/lib/console.py index 265c011..9674145 100644 --- a/system/lib/console.py +++ b/system/lib/console.py @@ -2,8 +2,8 @@ class Console: @staticmethod def progress_bar(message, current, total): percentage = (current + 1) * 100 // total - print('\r', end='') - print(f'[{percentage}%] {message}', end='') + print("\r", end="") + print(f"[{percentage}%] {message}", end="") if current + 1 == total: print() @@ -15,22 +15,23 @@ def percent(current: int, total: int) -> int: def ask_integer(message: str): while True: try: - return int(input(f'[????] {message}: ')) + return int(input(f"[????] {message}: ")) except ValueError: pass @staticmethod def question(message): - answer = None - while not answer in 'ny': - answer = input(f'[????] {message} [Y/n] ').lower() - - return 'ny'.index(answer) + while True: + answer = input(f"[????] {message} [Y/n] ").lower() + if answer in "ny": + break + + return "ny".index(answer) -if __name__ == '__main__': +if __name__ == "__main__": console = Console() - console.ask_integer('Please, type any integer') + console.ask_integer("Please, type any integer") for i in range(1000): - console.progress_bar('Test progress bar', i, 1000) + console.progress_bar("Test progress bar", i, 1000) diff --git a/system/lib/features/csv/compress.py b/system/lib/features/csv/compress.py index df721dc..ab62cb1 100644 --- a/system/lib/features/csv/compress.py +++ b/system/lib/features/csv/compress.py @@ -9,20 +9,27 @@ def compress_csv(): from sc_compression.signatures import Signatures - folder = './CSV/In-Decompressed' - folder_export = './CSV/Out-Compressed' + folder = "./CSV/In-Decompressed" + folder_export = "./CSV/Out-Compressed" for file in os.listdir(folder): - if file.endswith('.csv'): + if file.endswith(".csv"): try: - with open(f'{folder}/{file}', 'rb') as f: + with open(f"{folder}/{file}", "rb") as f: file_data = f.read() f.close() - with open(f'{folder_export}/{file}', 'wb') as f: + with open(f"{folder_export}/{file}", "wb") as f: f.write(compress(file_data, Signatures.LZMA)) f.close() except Exception as exception: - logger.exception(locale.error % (exception.__class__.__module__, exception.__class__.__name__, exception)) + logger.exception( + locale.error + % ( + exception.__class__.__module__, + exception.__class__.__name__, + exception, + ) + ) print() diff --git a/system/lib/features/csv/decompress.py b/system/lib/features/csv/decompress.py index 7296653..6006dcd 100644 --- a/system/lib/features/csv/decompress.py +++ b/system/lib/features/csv/decompress.py @@ -7,20 +7,27 @@ def decompress_csv(): - folder = './CSV/In-Compressed' - folder_export = './CSV/Out-Decompressed' + folder = "./CSV/In-Compressed" + folder_export = "./CSV/Out-Decompressed" for file in os.listdir(folder): - if file.endswith('.csv'): + if file.endswith(".csv"): try: - with open(f'{folder}/{file}', 'rb') as f: + with open(f"{folder}/{file}", "rb") as f: file_data = f.read() f.close() - with open(f'{folder_export}/{file}', 'wb') as f: + with open(f"{folder_export}/{file}", "wb") as f: f.write(decompress(file_data)[0]) f.close() except Exception as exception: - logger.exception(locale.error % (exception.__class__.__module__, exception.__class__.__name__, exception)) + logger.exception( + locale.error + % ( + exception.__class__.__module__, + exception.__class__.__name__, + exception, + ) + ) print() diff --git a/system/lib/features/cut_sprites.py b/system/lib/features/cut_sprites.py index c131bf4..f2089e7 100644 --- a/system/lib/features/cut_sprites.py +++ b/system/lib/features/cut_sprites.py @@ -6,9 +6,9 @@ def cut_sprites(swf: SupercellSWF, export_folder: str): - os.makedirs(f'{export_folder}/overwrite', exist_ok=True) - os.makedirs(f'{export_folder}/shapes', exist_ok=True) - os.makedirs(f'{export_folder}/movie_clips', exist_ok=True) + os.makedirs(f"{export_folder}/overwrite", exist_ok=True) + os.makedirs(f"{export_folder}/shapes", exist_ok=True) + os.makedirs(f"{export_folder}/movie_clips", exist_ok=True) # TODO: Too slow, fix it # movie_clips_skipped = 0 @@ -40,19 +40,18 @@ def cut_sprites(swf: SupercellSWF, export_folder: str): Console.progress_bar( locale.cut_sprites_process % (shape_index + 1, shapes_count), shape_index, - shapes_count + shapes_count, ) rendered_shape = shape.render() - rendered_shape.save(f'{export_folder}/shapes/{shape.id}.png') + rendered_shape.save(f"{export_folder}/shapes/{shape.id}.png") regions_count = len(shape.regions) for region_index in range(regions_count): region = shape.regions[region_index] - region.apply_matrix(None) - rendered_region = region.render() - rendered_region.save(f'{export_folder}/shape_{shape.id}_{region_index}.png') + rendered_region = region.render(use_original_size=True) + rendered_region.save(f"{export_folder}/shape_{shape.id}_{region_index}.png") for shape_index in range(shapes_count): shape = swf.shapes[shape_index] diff --git a/system/lib/features/directories.py b/system/lib/features/directories.py index 415e40b..b6b2aa0 100644 --- a/system/lib/features/directories.py +++ b/system/lib/features/directories.py @@ -3,16 +3,16 @@ def clear_directories(): - for i in ['In', 'Out']: - for k in ['Compressed', 'Decompressed', 'Sprites']: - folder = f'SC/{i}-{k}' + for i in ["In", "Out"]: + for k in ["Compressed", "Decompressed", "Sprites"]: + folder = f"SC/{i}-{k}" if os.path.isdir(folder): shutil.rmtree(folder) os.makedirs(folder, exist_ok=True) - for i in ['In', 'Out']: - for k in ['Compressed', 'Decompressed']: - folder = f'CSV/{i}-{k}' + for i in ["In", "Out"]: + for k in ["Compressed", "Decompressed"]: + folder = f"CSV/{i}-{k}" if os.path.isdir(folder): shutil.rmtree(folder) os.makedirs(folder, exist_ok=True) diff --git a/system/lib/features/files.py b/system/lib/features/files.py index 8a6faab..8b9d9c2 100644 --- a/system/lib/features/files.py +++ b/system/lib/features/files.py @@ -8,17 +8,17 @@ def write_sc(output_filename: str, buffer: bytes, use_lzham: bool): - with open(output_filename, 'wb') as file_out: + with open(output_filename, "wb") as file_out: logger.info(locale.header_done) if use_lzham: - logger.info(locale.compressing_with % 'LZHAM') - file_out.write(struct.pack('<4sBI', b'SCLZ', 18, len(buffer))) + logger.info(locale.compressing_with % "LZHAM") + file_out.write(struct.pack("<4sBI", b"SCLZ", 18, len(buffer))) compressed = compress(buffer, Signatures.SCLZ) file_out.write(compressed) else: - logger.info(locale.compressing_with % 'LZMA') + logger.info(locale.compressing_with % "LZMA") compressed = compress(buffer, Signatures.SC, 3) file_out.write(compressed) logger.info(locale.compression_done) @@ -29,13 +29,13 @@ def open_sc(input_filename: str): use_lzham = False logger.info(locale.collecting_inf) - with open(input_filename, 'rb') as f: + with open(input_filename, "rb") as f: file_data = f.read() f.close() try: - if b'START' in file_data: - file_data = file_data[:file_data.index(b'START')] + if b"START" in file_data: + file_data = file_data[: file_data.index(b"START")] decompressed_data, signature = decompress(file_data) # # logger.info(locale.detected_comp % signature.upper()) diff --git a/system/lib/features/initialization.py b/system/lib/features/initialization.py index 2889b80..0f6accb 100644 --- a/system/lib/features/initialization.py +++ b/system/lib/features/initialization.py @@ -17,26 +17,42 @@ def initialize(first_init=False): logger.info(locale.detected_os % platform.system()) logger.info(locale.installing) - required_packages = [pkg.rstrip('\n').lower() for pkg in open('requirements.txt').readlines()] + required_packages = [ + pkg.rstrip("\n").lower() for pkg in open("requirements.txt").readlines() + ] installed_packages = [pkg[0].lower() for pkg in get_pip_info()] for package in required_packages: if package in installed_packages: continue - if run(f'pip3 install {package}') == 0: + if run(f"pip3 install {package}") == 0: logger.info(locale.installed % package) else: logger.info(locale.not_installed % package) logger.info(locale.crt_workspace) - [[os.makedirs(f'SC/{i}-{k}', exist_ok=True) for k in ['Compressed', 'Decompressed', 'Sprites']] for i in ['In', 'Out']] - [[os.makedirs(f'CSV/{i}-{k}', exist_ok=True) for k in ['Compressed', 'Decompressed']] for i in ['In', 'Out']] + [ + [ + os.makedirs(f"SC/{i}-{k}", exist_ok=True) + for k in ["Compressed", "Decompressed", "Sprites"] + ] + for i in ["In", "Out"] + ] + [ + [ + os.makedirs(f"CSV/{i}-{k}", exist_ok=True) + for k in ["Compressed", "Decompressed"] + ] + for i in ["In", "Out"] + ] logger.info(locale.verifying) config.initialized = True try: + # noinspection PyUnresolvedReferences import requests + del requests - config.version = get_tags('vorono4ka', 'xcoder')[0]['name'][1:] + config.version = get_tags("vorono4ka", "xcoder")[0]["name"][1:] except ImportError as exception: logger.exception(exception) config.dump() diff --git a/system/lib/features/place_sprites.py b/system/lib/features/place_sprites.py index 53be7ef..a437d69 100644 --- a/system/lib/features/place_sprites.py +++ b/system/lib/features/place_sprites.py @@ -3,57 +3,67 @@ from PIL import Image, ImageDraw from system.lib import Console +from system.lib.helper import get_sides, get_size from system.lib.images import get_format_by_pixel_type from system.lib.xcod import parse_info, FileInfo from system.localization import locale -def place_sprites(xcod_path: str, folder: str, overwrite: bool = False) -> (list, FileInfo): +def place_sprites( + xcod_path: str, folder: str, overwrite: bool = False +) -> (list, FileInfo): file_info, xcod = parse_info(xcod_path) files_to_overwrite = os.listdir(f'{folder}{"/overwrite" if overwrite else ""}') - texture_files = os.listdir(f'{folder}/textures') + texture_files = os.listdir(f"{folder}/textures") sheets = [] for i in range(len(file_info.sheets)): sheet_info = file_info.sheets[i] sheets.append( - Image.open(f'{folder}/textures/{texture_files[i]}') - if overwrite else - Image.new(get_format_by_pixel_type(sheet_info.pixel_type), sheet_info.size) + Image.open(f"{folder}/textures/{texture_files[i]}") + if overwrite + else Image.new( + get_format_by_pixel_type(sheet_info.pixel_type), sheet_info.size + ) ) shapes_count = xcod.read_ushort() for shape_index in range(shapes_count): - Console.progress_bar(locale.place_sprites_process % (shape_index + 1, shapes_count), shape_index, shapes_count) + Console.progress_bar( + locale.place_sprites_process % (shape_index + 1, shapes_count), + shape_index, + shapes_count, + ) shape_id = xcod.read_ushort() regions_count = xcod.read_ushort() for region_index in range(regions_count): texture_id, points_count = xcod.read_uchar(), xcod.read_uchar() - texture_width, texture_height = sheets[texture_id].width, sheets[texture_id].height - polygon = [(xcod.read_ushort(), xcod.read_ushort()) for _ in range(points_count)] + texture_width, texture_height = ( + sheets[texture_id].width, + sheets[texture_id].height, + ) + points = [ + (xcod.read_ushort(), xcod.read_ushort()) for _ in range(points_count) + ] mirroring, rotation = xcod.read_uchar() == 1, xcod.read_char() * 90 - filename = f'shape_{shape_id}_{region_index}.png' + filename = f"shape_{shape_id}_{region_index}.png" if filename not in files_to_overwrite: continue - tmp_region = Image.open( - f'{folder}{"/overwrite" if overwrite else ""}/{filename}' - ).convert('RGBA').rotate(-rotation, expand=True) - - img_mask = Image.new('L', (texture_width, texture_height), 0) + img_mask = Image.new("L", (texture_width, texture_height), 0) color = 255 - ImageDraw.Draw(img_mask).polygon(polygon, fill=color) + ImageDraw.Draw(img_mask).polygon(points, fill=color) bbox = img_mask.getbbox() if not bbox: - min_x = min(i[0] for i in polygon) - min_y = min(i[1] for i in polygon) - max_x = max(i[0] for i in polygon) - max_y = max(i[1] for i in polygon) + min_x = min(i[0] for i in points) + min_y = min(i[1] for i in points) + max_x = max(i[0] for i in points) + max_y = max(i[1] for i in points) if max_y - min_y != 0: for _y in range(max_y - min_y): @@ -64,25 +74,28 @@ def place_sprites(xcod_path: str, folder: str, overwrite: bool = False) -> (list img_mask.putpixel((min_x + _x - 1, max_y - 1), color) else: img_mask.putpixel((max_x - 1, max_y - 1), color) - bbox = img_mask.getbbox() - left, top, right, bottom = bbox - if right - left - 1: - right -= 1 - if bottom - top - 1: - bottom -= 1 + left, top, right, bottom = get_sides(points) + if left == right: + right += 1 + if top == bottom: + bottom += 1 - bbox = left, top, right, bottom + width, height = get_size(left, top, right, bottom) - width = right - left - height = bottom - top - region_size = width, height - tmp_region = tmp_region.resize(region_size, Image.ANTIALIAS) + bbox = left, top, right, bottom + tmp_region = Image.open( + f'{folder}{"/overwrite" if overwrite else ""}/{filename}' + ).convert("RGBA") if mirroring: tmp_region = tmp_region.transpose(Image.FLIP_LEFT_RIGHT) + tmp_region = tmp_region.rotate(rotation, expand=True) + tmp_region = tmp_region.resize((width, height), Image.ANTIALIAS) - sheets[texture_id].paste(Image.new('RGBA', region_size), (left, top), img_mask.crop(bbox)) + sheets[texture_id].paste( + Image.new("RGBA", (width, height)), (left, top), img_mask.crop(bbox) + ) sheets[texture_id].paste(tmp_region, (left, top), tmp_region) print() diff --git a/system/lib/features/sc/__init__.py b/system/lib/features/sc/__init__.py index 0f6ee6a..c7ac78d 100644 --- a/system/lib/features/sc/__init__.py +++ b/system/lib/features/sc/__init__.py @@ -12,18 +12,20 @@ from system.localization import locale -def compile_sc(_dir, file_info: FileInfo, sheets: list = None, output_folder: str = None): - name = _dir.split('/')[-2] +def compile_sc( + _dir, file_info: FileInfo, sheets: list = None, output_folder: str = None +): + name = _dir.split("/")[-2] if sheets: files = sheets else: files = [] - [files.append(i) if i.endswith('.png') else None for i in os.listdir(_dir)] + [files.append(i) if i.endswith(".png") else None for i in os.listdir(_dir)] files.sort() if not files: - return logger.info(locale.dir_empty % _dir.split('/')[-2]) - files = [Image.open(f'{_dir}{i}') for i in files] + return logger.info(locale.dir_empty % _dir.split("/")[-2]) + files = [Image.open(f"{_dir}{i}") for i in files] logger.info(locale.collecting_inf) sc = Writer() @@ -39,7 +41,10 @@ def compile_sc(_dir, file_info: FileInfo, sheets: list = None, output_folder: st pixel_type = sheet_info.pixel_type if img.size != sheet_info.size: - logger.info(locale.illegal_size % (sheet_info.width, sheet_info.height, img.width, img.height)) + logger.info( + locale.illegal_size + % (sheet_info.width, sheet_info.height, img.width, img.height) + ) if Console.question(locale.resize_qu): logger.info(locale.resizing) @@ -52,7 +57,7 @@ def compile_sc(_dir, file_info: FileInfo, sheets: list = None, output_folder: st logger.info(locale.about_sc % (name, picture_index, pixel_type, width, height)) - sc.write(struct.pack(' list: - output = get_run_output(f'pip --disable-pip-version-check list {"-o" if outdated else ""}') + output = get_run_output( + f'pip --disable-pip-version-check list {"-o" if outdated else ""}' + ) output = output.splitlines() output = output[2:] packages = [package.split() for package in output] @@ -35,17 +37,18 @@ def get_pip_info(outdated: bool = False) -> list: def get_tags(owner: str, repo: str): - api_url = 'https://api.github.com' + api_url = "https://api.github.com" tags = [] import requests + try: - tags = requests.get(api_url + '/repos/{owner}/{repo}/tags'.format(owner=owner, repo=repo)).json() + tags = requests.get( + api_url + "/repos/{owner}/{repo}/tags".format(owner=owner, repo=repo) + ).json() tags = [ - { - key: v for key, v in tag.items() - if key in ['name', 'zipball_url'] - } for tag in tags + {key: v for key, v in tag.items() if key in ["name", "zipball_url"]} + for tag in tags ] except Exception: pass @@ -55,11 +58,11 @@ def get_tags(owner: str, repo: str): def check_update(): - tags = get_tags('vorono4ka', 'xcoder') + tags = get_tags("vorono4ka", "xcoder") if len(tags) > 0: latest_tag = tags[0] - latest_tag_name = latest_tag['name'][1:] # clear char 'v' at string start + latest_tag_name = latest_tag["name"][1:] # clear char 'v' at string start check_for_outdated() @@ -68,12 +71,14 @@ def check_update(): logger.error(locale.not_latest) logger.info(locale.update_downloading) - download_update(latest_tag['zipball_url']) + download_update(latest_tag["zipball_url"]) def check_for_outdated(): logger.info(locale.check_for_outdated) - required_packages = [pkg.rstrip('\n').lower() for pkg in open('requirements.txt').readlines()] + required_packages = [ + pkg.rstrip("\n").lower() for pkg in open("requirements.txt").readlines() + ] outdated_packages = [pkg[0].lower() for pkg in get_pip_info(True)] return [package for package in required_packages if package in outdated_packages] diff --git a/system/lib/features/update/download.py b/system/lib/features/update/download.py index fab04ce..0e89cbd 100644 --- a/system/lib/features/update/download.py +++ b/system/lib/features/update/download.py @@ -14,34 +14,34 @@ def update_outdated(outdated): def update_package(package): - run(f'pip3 install --upgrade {package}') + run(f"pip3 install --upgrade {package}") def download_update(zip_url): - if not os.path.exists('updates'): - os.mkdir('updates') + if not os.path.exists("updates"): + os.mkdir("updates") try: import requests - with open('updates/update.zip', 'wb') as f: + with open("updates/update.zip", "wb") as f: f.write(requests.get(zip_url).content) f.close() import zipfile - with zipfile.ZipFile('updates/update.zip') as zf: - zf.extractall('updates/') + with zipfile.ZipFile("updates/update.zip") as zf: + zf.extractall("updates/") zf.close() folder_name = f' "{zf.namelist()[0]}"' - logger.opt(colors=True).info(f'{locale.update_done % folder_name}') + logger.opt(colors=True).info( + f"{locale.update_done % folder_name}" + ) config.has_update = True config.last_update = int(time.time()) config.dump() input(locale.to_continue) exit() - - del requests except ImportError as exception: logger.exception(exception) diff --git a/system/lib/helper.py b/system/lib/helper.py index c38d7d1..0564338 100644 --- a/system/lib/helper.py +++ b/system/lib/helper.py @@ -15,7 +15,9 @@ def get_size(left: float, top: float, right: float, bottom: float) -> (int, int) return int(right - left), int(bottom - top) -def get_sides(points: List[Tuple[float, float]] or List[Point]) -> (float, float, float, float): +def get_sides( + points: List[Tuple[float, float]] or List[Point] +) -> (float, float, float, float): """Calculates and returns rect sides. :param points: polygon points @@ -34,7 +36,7 @@ def get_sides(points: List[Tuple[float, float]] or List[Point]) -> (float, float right = max(x for x, _ in points) bottom = max(y for _, y in points) else: - raise TypeError('Unknown point type.') + raise TypeError("Unknown point type.") return left, top, right, bottom - raise ValueError('Empty points list.') + raise ValueError("Empty points list.") diff --git a/system/lib/images.py b/system/lib/images.py index 9fe85d5..c7a222c 100644 --- a/system/lib/images.py +++ b/system/lib/images.py @@ -14,8 +14,8 @@ def load_image_from_buffer(img: Image) -> None: width, height = img.size img_loaded = img.load() - with open('pixel_buffer', 'rb') as pixel_buffer: - channels_count = int.from_bytes(pixel_buffer.read(1), 'little') + with open("pixel_buffer", "rb") as pixel_buffer: + channels_count = int.from_bytes(pixel_buffer.read(1), "little") for y in range(height): for x in range(width): @@ -23,8 +23,8 @@ def load_image_from_buffer(img: Image) -> None: def join_image(img: Image) -> None: - with open('pixel_buffer', 'rb') as pixel_buffer: - channels_count = int.from_bytes(pixel_buffer.read(1), 'little') + with open("pixel_buffer", "rb") as pixel_buffer: + channels_count = int.from_bytes(pixel_buffer.read(1), "little") width, height = img.size loaded_img = img.load() @@ -44,7 +44,9 @@ def join_image(img: Image) -> None: if pixel_x >= width: break - loaded_img[pixel_x, pixel_y] = tuple(pixel_buffer.read(channels_count)) + loaded_img[pixel_x, pixel_y] = tuple( + pixel_buffer.read(channels_count) + ) Console.progress_bar(locale.join_pic, y_chunk, y_chunks_count + 1) @@ -92,13 +94,13 @@ def get_pixel_size(_type): def get_format_by_pixel_type(_type): if _type in (0, 1, 2, 3): - return 'RGBA' + return "RGBA" elif _type == 4: - return 'RGB' + return "RGB" elif _type == 6: - return 'LA' + return "LA" elif _type == 10: - return 'L' + return "L" raise Exception(locale.unk_type % _type) @@ -107,27 +109,50 @@ def load_texture(data: Reader, _type, img): read_pixel = None channels_count = 4 if _type in (0, 1): + def read_pixel(): - return data.read_uchar(), data.read_uchar(), data.read_uchar(), data.read_uchar() + return ( + data.read_uchar(), + data.read_uchar(), + data.read_uchar(), + data.read_uchar(), + ) + elif _type == 2: + def read_pixel(): p = data.read_ushort() - return (p >> 12 & 15) << 4, (p >> 8 & 15) << 4, (p >> 4 & 15) << 4, (p >> 0 & 15) << 4 + return ( + (p >> 12 & 15) << 4, + (p >> 8 & 15) << 4, + (p >> 4 & 15) << 4, + (p >> 0 & 15) << 4, + ) + elif _type == 3: + def read_pixel(): p = data.read_ushort() - return (p >> 11 & 31) << 3, (p >> 6 & 31) << 3, (p >> 1 & 31) << 3, (p & 255) << 7 + return ( + (p >> 11 & 31) << 3, + (p >> 6 & 31) << 3, + (p >> 1 & 31) << 3, + (p & 255) << 7, + ) + elif _type == 4: channels_count = 3 def read_pixel(): p = data.read_ushort() return (p >> 11 & 31) << 3, (p >> 5 & 63) << 2, (p & 31) << 3 + elif _type == 6: channels_count = 2 def read_pixel(): return (data.read_uchar(), data.read_uchar())[::-1] + elif _type == 10: channels_count = 1 @@ -137,8 +162,8 @@ def read_pixel(): if read_pixel is None: return - with open('pixel_buffer', 'wb') as pixel_buffer: - pixel_buffer.write(channels_count.to_bytes(1, 'little')) + with open("pixel_buffer", "wb") as pixel_buffer: + pixel_buffer.write(channels_count.to_bytes(1, "little")) width, height = img.size point = -1 @@ -146,7 +171,7 @@ def read_pixel(): for x in range(width): pixel = read_pixel() for channel in pixel: - pixel_buffer.write(channel.to_bytes(1, 'little')) + pixel_buffer.write(channel.to_bytes(1, "little")) curr = Console.percent(y, height) if curr > point: @@ -157,26 +182,37 @@ def read_pixel(): def save_texture(sc, img, _type): write_pixel = None if _type in (0, 1): + def write_pixel(pixel): - return struct.pack('4B', *pixel) + return struct.pack("4B", *pixel) + if _type == 2: + def write_pixel(pixel): r, g, b, a = pixel - return struct.pack('> 4 | b >> 4 << 4 | g >> 4 << 8 | r >> 4 << 12) + return struct.pack("> 4 | b >> 4 << 4 | g >> 4 << 8 | r >> 4 << 12) + if _type == 3: + def write_pixel(pixel): r, g, b, a = pixel - return struct.pack('> 7 | b >> 3 << 1 | g >> 3 << 6 | r >> 3 << 11) + return struct.pack("> 7 | b >> 3 << 1 | g >> 3 << 6 | r >> 3 << 11) + if _type == 4: + def write_pixel(pixel): r, g, b = pixel - return struct.pack('> 3 | g >> 2 << 5 | r >> 3 << 11) + return struct.pack("> 3 | g >> 2 << 5 | r >> 3 << 11) + if _type == 6: + def write_pixel(pixel): - return struct.pack('2B', *pixel[::-1]) + return struct.pack("2B", *pixel[::-1]) + if _type == 10: + def write_pixel(pixel): - return struct.pack('B', pixel) + return struct.pack("B", pixel) if write_pixel is not None: width, height = img.size @@ -195,7 +231,7 @@ def write_pixel(pixel): def transform_image(image, scale_x, scale_y, angle, x, y): im_orig = image - image = Image.new('RGBA', im_orig.size, (255, 255, 255, 255)) + image = Image.new("RGBA", im_orig.size, (255, 255, 255, 255)) image.paste(im_orig) w, h = image.size @@ -206,8 +242,12 @@ def transform_image(image, scale_x, scale_y, angle, x, y): scaled_w, scaled_h = w * scale_x, h * scale_y - scaled_rotated_w = int(math.ceil(math.fabs(cos_theta * scaled_w) + math.fabs(sin_theta * scaled_h))) - scaled_rotated_h = int(math.ceil(math.fabs(sin_theta * scaled_w) + math.fabs(cos_theta * scaled_h))) + scaled_rotated_w = int( + math.ceil(math.fabs(cos_theta * scaled_w) + math.fabs(sin_theta * scaled_h)) + ) + scaled_rotated_h = int( + math.ceil(math.fabs(sin_theta * scaled_w) + math.fabs(cos_theta * scaled_h)) + ) translated_w = int(math.ceil(scaled_rotated_w + math.fabs(x))) translated_h = int(math.ceil(scaled_rotated_h + math.fabs(y))) @@ -216,10 +256,10 @@ def transform_image(image, scale_x, scale_y, angle, x, y): if y > 0: y = 0 - cx = w / 2. - cy = h / 2. - translate_x = scaled_rotated_w / 2. - x - translate_y = scaled_rotated_h / 2. - y + cx = w / 2.0 + cy = h / 2.0 + translate_x = scaled_rotated_w / 2.0 - x + translate_y = scaled_rotated_h / 2.0 - y a = cos_theta / scale_x b = sin_theta / scale_x @@ -228,7 +268,12 @@ def transform_image(image, scale_x, scale_y, angle, x, y): e = cos_theta / scale_y f = cy - translate_x * d - translate_y * e - return image.transform((translated_w, translated_h), Image.AFFINE, (a, b, c, d, e, f), resample=Image.BILINEAR) + return image.transform( + (translated_w, translated_h), + Image.AFFINE, + (a, b, c, d, e, f), + resample=Image.BILINEAR, + ) def translate_image(image, x, y): @@ -241,19 +286,25 @@ def translate_image(image, x, y): if y > 0: y = 0 - return image.transform((translated_w, translated_h), Image.AFFINE, (1, 0, -x, 0, 1, -y), resample=Image.BILINEAR) + return image.transform( + (translated_w, translated_h), + Image.AFFINE, + (1, 0, -x, 0, 1, -y), + resample=Image.BILINEAR, + ) def transform_image_by_matrix(image, matrix: list or tuple): scale_x, rotation_x, x = matrix[:3] rotation_y, scale_y, y = matrix[3:] - return transform_image(image, scale_x, scale_y, math.atan2(rotation_x, rotation_y), x, y) + return transform_image( + image, scale_x, scale_y, math.atan2(rotation_x, rotation_y), x, y + ) -if __name__ == '__main__': +if __name__ == "__main__": transform_image_by_matrix( - Image.open('../../test_0.png'), - [1.0458984375, 0.0, -127.65, - 0.0, 1.0458984375, -700.] + Image.open("../../test_0.png"), + [1.0458984375, 0.0, -127.65, 0.0, 1.0458984375, -700.0], ).show() input() diff --git a/system/lib/matrices/matrix2x3.py b/system/lib/matrices/matrix2x3.py index c15d3f6..dddb5b4 100644 --- a/system/lib/matrices/matrix2x3.py +++ b/system/lib/matrices/matrix2x3.py @@ -20,7 +20,7 @@ def load(self, reader: Reader, tag: int): elif tag == 36: divider = PRECISE_MULTIPLIER else: - raise ValueError(f'Unsupported matrix tag: {tag}') + raise ValueError(f"Unsupported matrix tag: {tag}") self.scale_x = reader.read_int() / divider self.shear_x = reader.read_int() / divider diff --git a/system/lib/matrices/matrix_bank.py b/system/lib/matrices/matrix_bank.py index 0d80839..59fe031 100644 --- a/system/lib/matrices/matrix_bank.py +++ b/system/lib/matrices/matrix_bank.py @@ -23,4 +23,3 @@ def get_matrix(self, index: int) -> Matrix2x3: def get_color_transform(self, index: int) -> ColorTransform: return self.color_transforms[index] - diff --git a/system/lib/menu.py b/system/lib/menu.py index d6e8c6b..2cdf010 100644 --- a/system/lib/menu.py +++ b/system/lib/menu.py @@ -8,21 +8,31 @@ from system.localization import locale -def print_feature(feature_id: int, name: str, description: str = None, console_width: int = -1): - text = f' {feature_id} {name}' +def print_feature( + feature_id: int, name: str, description: str = None, console_width: int = -1 +): + text = f" {feature_id} {name}" if description: - text += ' ' * (console_width // 2 - len(text)) + ': ' + description + text += " " * (console_width // 2 - len(text)) + ": " + description print(textwrap.fill(text, console_width)) def print_category(text: str, background_width: int = 10): - print(colorama.Back.GREEN + colorama.Fore.BLACK + text + ' ' * (background_width - len(text)) + colorama.Style.RESET_ALL) + print( + colorama.Back.GREEN + + colorama.Fore.BLACK + + text + + " " * (background_width - len(text)) + + colorama.Style.RESET_ALL + ) class Menu: class Item: - def __init__(self, name: str, description: str = None, handler: typing.Callable = None): + def __init__( + self, name: str, description: str = None, handler: typing.Callable = None + ): self.name: str = name self.description: str = description self.handler: typing.Callable = handler @@ -36,6 +46,7 @@ def __init__(self, _id: int, name: str): def item(self, name, description): def wrapper(handler): self.add(Menu.Item(name, description, handler)) + return wrapper def add(self, item): @@ -50,19 +61,27 @@ def add_category(self, category): def choice(self): console_width = shutil.get_terminal_size().columns - print(( - colorama.Back.BLACK + colorama.Fore.GREEN + - locale.xcoder_header % config.version + - colorama.Style.RESET_ALL - ).center(console_width + 12)) - print('github.com/Vorono4ka/XCoder'.center(console_width - 1)) + print( + ( + colorama.Back.BLACK + + colorama.Fore.GREEN + + locale.xcoder_header % config.version + + colorama.Style.RESET_ALL + ).center(console_width + 12) + ) + print("github.com/Vorono4ka/XCoder".center(console_width - 1)) self._print_divider_line(console_width) for category in self.categories: print_category(category.name) for item_index in range(len(category.items)): item = category.items[item_index] - print_feature(category.id * 10 + item_index + 1, item.name, item.description, console_width) + print_feature( + category.id * 10 + item_index + 1, + item.name, + item.description, + console_width, + ) self._print_divider_line(console_width) choice = input(locale.choice) @@ -86,7 +105,7 @@ def choice(self): @staticmethod def _print_divider_line(console_width: int): - print((console_width - 1) * '-') + print((console_width - 1) * "-") menu = Menu() diff --git a/system/lib/objects/movie_clip.py b/system/lib/objects/movie_clip.py index f3a0f24..d767d76 100644 --- a/system/lib/objects/movie_clip.py +++ b/system/lib/objects/movie_clip.py @@ -55,7 +55,7 @@ def load(self, swf, tag: int): self.fps = swf.reader.read_char() self.frames_count = swf.reader.read_ushort() - if tag in (3, 14,): + if tag in (3, 14): pass else: transforms_count = swf.reader.read_uint() @@ -65,7 +65,9 @@ def load(self, swf, tag: int): matrix_index = swf.reader.read_ushort() color_transform_index = swf.reader.read_ushort() - self.frame_elements.append((child_index, matrix_index, color_transform_index)) + self.frame_elements.append( + (child_index, matrix_index, color_transform_index) + ) binds_count = swf.reader.read_ushort() @@ -73,7 +75,7 @@ def load(self, swf, tag: int): bind_id = swf.reader.read_ushort() # bind_id self.binds.append(bind_id) - if tag in (12, 35,): + if tag in (12, 35): for i in range(binds_count): blend = swf.reader.read_char() # blend self.blends.append(blend) @@ -93,7 +95,11 @@ def load(self, swf, tag: int): if frame_tag == 11: frame = MovieClipFrame() frame.load(swf.reader) - frame.set_elements(self.frame_elements[elements_used:elements_used + frame.get_elements_count()]) + frame.set_elements( + self.frame_elements[ + elements_used : elements_used + frame.get_elements_count() + ] + ) self.frames.append(frame) elements_used += frame.get_elements_count() @@ -110,7 +116,7 @@ def render(self, swf, matrix=None) -> Image: width, height = get_size(left, top, right, bottom) size = ceil(width), ceil(height) - image = Image.new('RGBA', size) + image = Image.new("RGBA", size) frame = self.frames[0] for child_index, matrix_index, _ in frame.get_elements(): @@ -151,7 +157,12 @@ def get_sides(self, swf) -> Tuple[float, float, float, float]: if isinstance(display_object, Shape): display_object.apply_matrix(matrix) - shape_left, shape_top, shape_right, shape_bottom = display_object.get_sides() + ( + shape_left, + shape_top, + shape_right, + shape_bottom, + ) = display_object.get_sides() left = min(left, shape_left) top = min(top, shape_top) diff --git a/system/lib/objects/point.py b/system/lib/objects/point.py index 11391d3..9f83403 100644 --- a/system/lib/objects/point.py +++ b/system/lib/objects/point.py @@ -2,7 +2,7 @@ class Point: def __init__(self, x: float = 0, y: float = 0): self.x: float = x self.y: float = y - + def __eq__(self, other): if isinstance(other, Point): return self.x == other.x and self.y == other.y diff --git a/system/lib/objects/shape.py b/system/lib/objects/shape.py index c13a783..6693d33 100644 --- a/system/lib/objects/shape.py +++ b/system/lib/objects/shape.py @@ -1,5 +1,5 @@ from math import ceil, degrees, atan2 -from typing import List, Tuple +from typing import List, Tuple, Optional from PIL import Image, ImageDraw @@ -26,7 +26,7 @@ def load(self, swf, tag: int): if region_tag == 0: return - elif region_tag in (4, 17, 22,): + elif region_tag in (4, 17, 22): region = Region() region.load(swf, region_tag) self.regions.append(region) @@ -42,7 +42,7 @@ def render(self, matrix=None): width, height = get_size(shape_left, shape_top, shape_right, shape_bottom) size = ceil(width), ceil(height) - image = Image.new('RGBA', size) + image = Image.new("RGBA", size) for region in self.regions: rendered_region = region.render() @@ -115,8 +115,16 @@ def load(self, swf, tag: int): self._xy_points[i].x = swf.reader.read_int() / 20 self._xy_points[i].y = swf.reader.read_int() / 20 for i in range(self._points_count): - u, v = (swf.reader.read_ushort() * swf.textures[self.texture_index].width / 0xffff * multiplier, - swf.reader.read_ushort() * swf.textures[self.texture_index].height / 0xffff * multiplier) + u, v = ( + swf.reader.read_ushort() + * swf.textures[self.texture_index].width + / 0xFFFF + * multiplier, + swf.reader.read_ushort() + * swf.textures[self.texture_index].height + / 0xFFFF + * multiplier, + ) u_rounded, v_rounded = map(ceil, (u, v)) if int(u) == u_rounded: u_rounded += 1 @@ -125,8 +133,8 @@ def load(self, swf, tag: int): self._uv_points[i].position = (u_rounded, v_rounded) - def render(self): - self._transformed_points = self._xy_points + def render(self, use_original_size: bool = False) -> Image.Image: + self.apply_matrix(None) left, top, right, bottom = self.get_sides() width, height = get_size(left, top, right, bottom) @@ -143,22 +151,25 @@ def render(self): drawable_image = ImageDraw.Draw(rendered_polygon) drawable_image.polygon( [(point.x - left, point.y - top) for point in self._transformed_points], - fill=fill_color + fill=fill_color, ) return rendered_polygon rendered_region = rendered_region.rotate(-self.rotation, expand=True) if self.is_mirrored: rendered_region = rendered_region.transpose(Image.FLIP_LEFT_RIGHT) - rendered_region = rendered_region.resize((width, height), Image.ANTIALIAS) - return rendered_region + if use_original_size: + return rendered_region + return rendered_region.resize((width, height), Image.ANTIALIAS) def get_image(self) -> Image: left, top, right, bottom = get_sides(self._uv_points) width, height = get_size(left, top, right, bottom) width, height = max(width, 1), max(height, 1) if width + height == 1: # The same speed as without this return - return Image.new('RGBA', (width, height), color=self.texture.image.get_pixel(left, top)) + return Image.new( + "RGBA", (width, height), color=self.texture.image.get_pixel(left, top) + ) if width == 1: right += 1 @@ -169,11 +180,15 @@ def get_image(self) -> Image: bbox = left, top, right, bottom color = 255 - img_mask = Image.new('L', (self.texture.width, self.texture.height), 0) - ImageDraw.Draw(img_mask).polygon([point.position for point in self._uv_points], fill=color) + img_mask = Image.new("L", (self.texture.width, self.texture.height), 0) + ImageDraw.Draw(img_mask).polygon( + [point.position for point in self._uv_points], fill=color + ) - rendered_region = Image.new('RGBA', (width, height)) - rendered_region.paste(self.texture.image.crop(bbox), (0, 0), img_mask.crop(bbox)) + rendered_region = Image.new("RGBA", (width, height)) + rendered_region.paste( + self.texture.image.crop(bbox), (0, 0), img_mask.crop(bbox) + ) return rendered_region @@ -205,7 +220,7 @@ def get_position(self) -> Tuple[float, float]: def get_sides(self) -> Tuple[float, float, float, float]: return get_sides(self._transformed_points) - def apply_matrix(self, matrix: Matrix2x3 = None) -> None: + def apply_matrix(self, matrix: Optional[Matrix2x3] = None) -> None: """Applies affine matrix to shape (xy) points. If matrix is none, copies the points. :param matrix: Affine matrix @@ -215,12 +230,16 @@ def apply_matrix(self, matrix: Matrix2x3 = None) -> None: if matrix is not None: self._transformed_points = [] for point in self._xy_points: - self._transformed_points.append(Point( - matrix.apply_x(point.x, point.y), - matrix.apply_y(point.x, point.y) - )) - - def calculate_rotation(self, round_to_nearest: bool = False, custom_points: List[Point] = None) -> (int, bool): + self._transformed_points.append( + Point( + matrix.apply_x(point.x, point.y), + matrix.apply_y(point.x, point.y), + ) + ) + + def calculate_rotation( + self, round_to_nearest: bool = False, custom_points: List[Point] = None + ) -> (int, bool): """Calculates rotation and if region is mirrored. :param round_to_nearest: should round to a multiple of 90 diff --git a/system/lib/objects/texture.py b/system/lib/objects/texture.py index 8679787..5e574cd 100644 --- a/system/lib/objects/texture.py +++ b/system/lib/objects/texture.py @@ -2,7 +2,12 @@ from PIL import Image -from system.lib.images import get_format_by_pixel_type, load_texture, join_image, load_image_from_buffer +from system.lib.images import ( + get_format_by_pixel_type, + load_texture, + join_image, + load_image_from_buffer, +) class SWFTexture: @@ -19,7 +24,9 @@ def load(self, swf, tag: int, has_texture: bool): self.width, self.height = (swf.reader.read_ushort(), swf.reader.read_ushort()) if has_texture: - img = Image.new(get_format_by_pixel_type(self.pixel_type), (self.width, self.height)) + img = Image.new( + get_format_by_pixel_type(self.pixel_type), (self.width, self.height) + ) load_texture(swf.reader, self.pixel_type, img) @@ -28,6 +35,6 @@ def load(self, swf, tag: int, has_texture: bool): else: load_image_from_buffer(img) - os.remove('pixel_buffer') + os.remove("pixel_buffer") self.image = img diff --git a/system/lib/swf.py b/system/lib/swf.py index 7b82ff1..2ba8c79 100644 --- a/system/lib/swf.py +++ b/system/lib/swf.py @@ -10,8 +10,8 @@ from system.lib.objects import Shape, MovieClip, SWFTexture from system.localization import locale -DEFAULT_HIGHRES_SUFFIX = '_highres' -DEFAULT_LOWRES_SUFFIX = '_lowres' +DEFAULT_HIGHRES_SUFFIX = "_highres" +DEFAULT_LOWRES_SUFFIX = "_lowres" class SupercellSWF: @@ -19,7 +19,7 @@ class SupercellSWF: SHAPES_TAGS = (2, 18) MOVIE_CLIPS_TAGS = (3, 10, 12, 14, 35) - TEXTURE_EXTENSION = '_tex.sc' + TEXTURE_EXTENSION = "_tex.sc" def __init__(self): self.filename: str or None = None @@ -33,7 +33,7 @@ def __init__(self): self.movie_clips: List[MovieClip] = [] self.textures: List[SWFTexture] = [] - self.xcod_writer = Writer('big') + self.xcod_writer = Writer("big") self._filepath: str or None = None @@ -55,11 +55,15 @@ def __init__(self): def load(self, filepath: str) -> (bool, bool): self._filepath = filepath - texture_loaded, use_lzham = self._load_internal(filepath, filepath.endswith('_tex.sc')) + texture_loaded, use_lzham = self._load_internal( + filepath, filepath.endswith("_tex.sc") + ) if not texture_loaded: if self.use_uncommon_texture: - texture_loaded, use_lzham = self._load_internal(self.uncommon_texture_path, True) + texture_loaded, use_lzham = self._load_internal( + self.uncommon_texture_path, True + ) else: texture_path = self._filepath[:-3] + SupercellSWF.TEXTURE_EXTENSION texture_loaded, use_lzham = self._load_internal(texture_path, True) @@ -87,7 +91,9 @@ def _load_internal(self, filepath: str, is_texture: bool) -> (bool, bool): self._matrix_banks.append(self._matrix_bank) self.shapes = [_class() for _class in [Shape] * self._shape_count] - self.movie_clips = [_class() for _class in [MovieClip] * self._movie_clip_count] + self.movie_clips = [ + _class() for _class in [MovieClip] * self._movie_clip_count + ] self.textures = [_class() for _class in [SWFTexture] * self._texture_count] self.reader.read_uint() @@ -109,7 +115,9 @@ def _load_internal(self, filepath: str, is_texture: bool) -> (bool, bool): export_id = self._export_ids[i] export_name = self._export_names[i] - movie_clip = self.get_display_object(export_id, export_name, raise_error=True) + movie_clip = self.get_display_object( + export_id, export_name, raise_error=True + ) movie_clip.export_name = export_name print() @@ -134,13 +142,16 @@ def _load_tags(self): texture.load(self, tag, has_texture) if has_texture: - logger.info(locale.about_sc % ( - self.filename, - texture_id, - texture.pixel_type, - texture.width, - texture.height - )) + logger.info( + locale.about_sc + % ( + self.filename, + texture_id, + texture.pixel_type, + texture.width, + texture.height, + ) + ) print() self.xcod_writer.write_ubyte(tag) @@ -162,11 +173,21 @@ def _load_tags(self): has_texture = False elif tag == 30: self.use_uncommon_texture = True - highres_texture_path = self._filepath[:-3] + self._highres_suffix + SupercellSWF.TEXTURE_EXTENSION - lowres_texture_path = self._filepath[:-3] + self._lowres_suffix + SupercellSWF.TEXTURE_EXTENSION + highres_texture_path = ( + self._filepath[:-3] + + self._highres_suffix + + SupercellSWF.TEXTURE_EXTENSION + ) + lowres_texture_path = ( + self._filepath[:-3] + + self._lowres_suffix + + SupercellSWF.TEXTURE_EXTENSION + ) self.uncommon_texture_path = highres_texture_path - if not os.path.exists(highres_texture_path) and os.path.exists(lowres_texture_path): + if not os.path.exists(highres_texture_path) and os.path.exists( + lowres_texture_path + ): self.uncommon_texture_path = lowres_texture_path self.use_lowres_texture = True elif tag == 42: @@ -181,7 +202,9 @@ def _load_tags(self): else: self.reader.read(length) - def get_display_object(self, target_id: int, name: str or None = None, *, raise_error: bool = False): + def get_display_object( + self, target_id: int, name: str or None = None, *, raise_error: bool = False + ): for shape in self.shapes: if shape.id == target_id: return shape @@ -191,9 +214,11 @@ def get_display_object(self, target_id: int, name: str or None = None, *, raise_ return movie_clip if raise_error: - exception_text = f'Unable to find some DisplayObject id {target_id}, {self.filename}' + exception_text = ( + f"Unable to find some DisplayObject id {target_id}, {self.filename}" + ) if name is not None: - exception_text += f' needed by export name {name}' + exception_text += f" needed by export name {name}" raise ValueError(exception_text) return None diff --git a/system/lib/xcod.py b/system/lib/xcod.py index ac40ad0..221cde9 100644 --- a/system/lib/xcod.py +++ b/system/lib/xcod.py @@ -26,12 +26,12 @@ class FileInfo: def parse_info(xcod_path: str) -> (FileInfo, Reader): - with open(xcod_path, 'rb') as file: - xcod = Reader(file.read(), 'big') + with open(xcod_path, "rb") as file: + xcod = Reader(file.read(), "big") magic = xcod.read(4) - if magic != b'XCOD': - raise IOError('Unknown file MAGIC: ' + magic.hex()) + if magic != b"XCOD": + raise IOError("Unknown file MAGIC: " + magic.hex()) use_lzham = xcod.read_uchar() == 1 diff --git a/system/localization.py b/system/localization.py index ad86714..94b6998 100644 --- a/system/localization.py +++ b/system/localization.py @@ -96,12 +96,12 @@ def __init__(self): self.install_to_unlock = None def load(self, language: str): - language_filepath = './system/languages/' + language + '.json' - english_language_filepath = './system/languages/en-EU.json' + language_filepath = "./system/languages/" + language + ".json" + english_language_filepath = "./system/languages/en-EU.json" loaded_locale = {} if os.path.exists(language_filepath): - loaded_locale = json.load(open(language_filepath, encoding='utf-8')) # Any + loaded_locale = json.load(open(language_filepath, encoding="utf-8")) # Any english_locale = json.load(open(english_language_filepath)) # English for key in self.__dict__: @@ -111,22 +111,22 @@ def load(self, language: str): setattr(self, key, english_locale[key]) def change(self): - language_files = os.listdir('./system/languages/') + language_files = os.listdir("./system/languages/") - print('Select Language\nВыберите язык\nВиберіть Мову\n') + print("Select Language\nВыберите язык\nВиберіть Мову\n") for file_index in range(len(language_files)): - language_path = './system/languages/' + language_files[file_index] - language_name = json.load(open(language_path, encoding='utf-8'))['name'] + language_path = "./system/languages/" + language_files[file_index] + language_name = json.load(open(language_path, encoding="utf-8"))["name"] - print(f'{file_index + 1} - {language_name}') + print(f"{file_index + 1} - {language_name}") - language_index = input('\n>>> ') + language_index = input("\n>>> ") try: language_index = int(language_index) - 1 if language_index >= 0: if language_index < len(language_files): - language = '.'.join(language_files[language_index].split('.')[:-1]) + language = ".".join(language_files[language_index].split(".")[:-1]) self.load(language) return language