diff --git a/atlasimagecomposer/backend/compose.py b/atlasimagecomposer/backend/compose.py index a896310..b1d0be5 100644 --- a/atlasimagecomposer/backend/compose.py +++ b/atlasimagecomposer/backend/compose.py @@ -1,7 +1,7 @@ import pathlib from typing import List, Optional +from collections import Counter -import numpy as np from PIL import Image from tqdm.contrib import itertools as tqdm_itertools @@ -44,10 +44,10 @@ def gen_main_sprite(folder: pathlib.Path): def process_sprite(images_folder: pathlib.Path, configdata: SpritesheetData, outputfolder: pathlib.Path): main_sprite = gen_main_sprite(images_folder) - save_sprite(main_sprite, outputfolder, f"{images_folder.stem}") + image_idx = save_sprite(main_sprite, outputfolder, f"{images_folder.stem}") for i in images_folder.iterdir(): - initial_row, index = 0, int(i.stem) + initial_row = 0 expressions = Image.open(i) rowcount, colcount = calculate_counts(*expressions.size, configdata["facesize"]) @@ -61,7 +61,7 @@ def process_sprite(images_folder: pathlib.Path, configdata: SpritesheetData, out for x, y in tqdm_itertools.product(range(initial_row, rowcount), range(0, colcount), ascii="-="): img = generate_sprite(main_sprite, expressions, x, y, configdata) if img is not None: - save_sprite(img, outputfolder, f"{images_folder.stem}", (x, y, colcount, index)) + image_idx = save_sprite(img, outputfolder, f"{images_folder.stem}", image_idx) def generate_sprite(main_sprite: Image.Image, expressions: Image.Image, row: int, col: int, configdata: SpritesheetData) -> Image.Image | None: @@ -69,53 +69,34 @@ def generate_sprite(main_sprite: Image.Image, expressions: Image.Image, row: int roi = ( col * facesize[0], row * facesize[1], - (col + 1) * facesize[0] - 1, - (row + 1) * facesize[1] - 1 + (col + 1) * facesize[0], + (row + 1) * facesize[1] ) - expression = expressions.crop(roi) if is_empty(expression): return None + mask = Image.new("RGBA", (facesize[0], facesize[1]), (255,255,255,255)) composition = main_sprite.copy() - composition.paste(expression, position, expression) + composition.paste(expression, position, mask) return composition -def save_sprite(image: Image.Image, outputfolder: pathlib.Path, name: str, info: tuple | None = None): +def save_sprite(image: Image.Image, outputfolder: pathlib.Path, name: str, idx: int = 0) -> int: savefolder = outputfolder / name if not savefolder.is_dir(): savefolder.mkdir() - - postfix = "0" - - if info is not None: - (row, col, column_count, file_idx) = info - - if file_idx == 0 and column_count == 4: - postfix = str(col + 1) - elif file_idx == 0: - raise ValueError("Should not have any faces") - elif column_count == 4: - postfix = str((column_count * row + col + 1) + pow(column_count, 2) * (file_idx - 1) + column_count) - elif column_count == 1: - postfix = str((file_idx - 1) * 16 + 1 if file_idx >= 2 else file_idx * 4 + 1) - elif column_count < 4: - postfix = str((column_count * row + col + 1) + pow(column_count, 2) * (file_idx - 1)) - else: - raise ValueError("Unaccounted case") - - outfile = savefolder / f"{postfix}.png" + outfile = savefolder / f"{idx}.png" with open(outfile, 'wb') as file: image.save(file) + idx += 1 + return idx def is_empty(img: Image.Image): - data = np.asarray(img.crop((96, 96, 160, 160)).convert('LA')) - np.reshape(data, (-1, 1)) - _, count_unique = np.unique(data, return_counts=True) - if count_unique.size < 10: + data = Counter(img.crop((96, 96, 160, 160)).convert('LA').getdata()) + if len(data) < 10: return True return False diff --git a/atlasimagecomposer/cli/cli.py b/atlasimagecomposer/cli/cli.py index 34638be..0f2ba5e 100644 --- a/atlasimagecomposer/cli/cli.py +++ b/atlasimagecomposer/cli/cli.py @@ -15,6 +15,7 @@ class Arguments(argparse.Namespace): Default Arguments when calling the CLI """ output: str + id: str cacheclear: bool filter: List[str] timeout: int @@ -31,9 +32,10 @@ def parse_arguments(): parser.add_argument("--version", action="version", version=f"atlasimagecomposer {__version__}") parser.add_argument("--output", action="store", type=str, default=None, dest="output", help="Set the output location. This can be an absolute or relative path") + parser.add_argument("--id", action="store", type=str, default=None, dest="id", help="Set the servantId/charaId - Skips user prompt when provided") parser.add_argument("--filter", action="extend", nargs="+", dest="filter", help='Specify one or more spritesheet ids that will be fetched') parser.add_argument("--timeout", action="store", type=int, default=None, dest="timeout", help="Set the timeout for all requests towards AtlasAcademy, default is 10s") - parser.add_argument("--clear-cache", action="store_true", default=False, dest="cacheclear", help="Clear cached assets before downloading files for a servant") + parser.add_argument("--clear-cache", action="store_true", default=False, dest="cacheclear", help="Clear cached assets before downloading files") args = Arguments() @@ -56,7 +58,10 @@ def run_cli(): welcome() - input_id = input("Enter servantId/charaId: ") + input_id = args.id + if not input_id: + input_id = input("Enter servantId/charaId: ") + try: t = int(input_id) if t <= 0: @@ -65,6 +70,8 @@ def run_cli(): print("Servant ID has to be a valid integer above 0") sys.exit(1) + input_id = int(input_id) + if args.cacheclear: cachepath = Paths.IMAGES / str(input_id) if input_id > 10000: @@ -75,4 +82,4 @@ def run_cli(): else: print("No cache to clear was found, continuing") - compose(int(input_id), args.filter) + compose(input_id, args.filter) diff --git a/pyproject.toml b/pyproject.toml index 10c4b2b..d0dd54c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,6 @@ [project] name = "atlasimagecomposer" -version = "0.1.0-c.2" -dependencies = [ - "numpy~=2.0.1", - "pillow~=10.4.0", - "requests~=2.32.3", - "tqdm~=4.66.5", -] +version = "0.1.0-c.3" requires-python = ">= 3.10" authors = [{name = "Firq", email = "firelp42@gmail.com"}] maintainers = [{name = "Firq", email = "firelp42@gmail.com"}] @@ -19,15 +13,11 @@ classifiers = [ "Programming Language :: Python :: 3.12", ] -[project.scripts] -atlasimagecomposer = "atlasimagecomposer.cli.cli:run_cli" - -[tool.setuptools.packages.find] -where = ["."] -include = ["atlasimagecomposer*"] - -[tool.setuptools.package-data] -"*" = ["py.typed"] +dependencies = [ + "pillow~=10.4.0", + "requests~=2.32.3", + "tqdm~=4.66.5", +] [project.optional-dependencies] lint = [ @@ -39,6 +29,16 @@ typing = [ "types-requests~=2.32.0", ] +[project.scripts] +atlasimagecomposer = "atlasimagecomposer.cli.cli:run_cli" + +[tool.setuptools.packages.find] +where = ["."] +include = ["atlasimagecomposer*"] + +[tool.setuptools.package-data] +"*" = ["py.typed"] + [tool.pylint."MAIN"] disable = [ "line-too-long",