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