skyeweave/atlasimagecomposer/backend/compose.py

118 lines
3.6 KiB
Python
Raw Normal View History

2024-08-09 16:57:33 +00:00
import pathlib
2024-10-05 12:01:50 +00:00
from typing import List, Optional
2024-08-09 16:57:33 +00:00
import numpy as np
from PIL import Image
from tqdm.contrib import itertools as tqdm_itertools
2024-10-05 12:01:50 +00:00
from ..config import Paths
from .atlas import SpritesheetData, fetch_data, fetch_expression_sheets
2024-08-09 16:57:33 +00:00
2024-10-05 12:01:50 +00:00
def compose(servantid: int, filters: Optional[List[str]] = None):
2024-08-09 16:57:33 +00:00
Paths.IMAGES.mkdir(exist_ok=True)
Paths.OUTPUT.mkdir(exist_ok=True)
sprites = fetch_data(servantid)
2024-10-05 12:01:50 +00:00
if filters is not None:
sprites = { key: value for key, value in sprites.items() if key in filters }
2024-08-09 16:57:33 +00:00
for sprite in sprites:
2024-10-05 12:01:50 +00:00
fetch_expression_sheets(servantid, sprite)
2024-08-09 16:57:33 +00:00
2024-10-05 12:01:50 +00:00
path = Paths.IMAGES / str(servantid)
2024-08-09 16:57:33 +00:00
2024-10-05 12:01:50 +00:00
savefolder = Paths.OUTPUT / str(servantid)
if not savefolder.is_dir():
savefolder.mkdir()
2024-10-04 18:18:56 +00:00
2024-10-05 12:01:50 +00:00
for f in path.iterdir():
if filters is not None and str(f.stem) not in filters:
continue
process_sprite(f, servantid, sprites[f.stem])
2024-10-04 18:18:56 +00:00
2024-10-05 12:01:50 +00:00
print(f"Files have been saved at: {(Paths.OUTPUT / str(servantid)).absolute()}")
2024-10-04 18:18:56 +00:00
2024-10-05 12:01:50 +00:00
def calculate_counts(width: int, height: int, facesize: int):
return height // facesize, width // facesize
2024-10-04 18:18:56 +00:00
2024-10-05 12:01:50 +00:00
def process_sprite(images_folder: pathlib.Path, servantid: int, configdata: SpritesheetData):
main = Image.open(images_folder / "0.png")
2024-10-04 18:18:56 +00:00
2024-10-05 12:01:50 +00:00
width, _ = main.size
main_sprite = main.crop((0, 0, width, 756))
2024-10-04 18:18:56 +00:00
2024-10-05 12:01:50 +00:00
save_sprite(main_sprite, servantid, f"{images_folder.stem}")
2024-08-09 16:57:33 +00:00
2024-10-05 12:01:50 +00:00
for i in images_folder.iterdir():
initial_row, index = 0, int(i.stem)
expressions = Image.open(i)
2024-08-09 16:57:33 +00:00
2024-10-05 12:01:50 +00:00
rowcount, colcount = calculate_counts(*expressions.size, configdata["facesize"])
2024-10-04 17:30:40 +00:00
2024-10-05 12:01:50 +00:00
if i.name == "0.png":
initial_row = 3
2024-10-04 17:30:40 +00:00
2024-10-05 12:01:50 +00:00
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, servantid, f"{images_folder.stem}", (x, y, colcount, index))
2024-10-04 17:30:40 +00:00
2024-08-09 16:57:33 +00:00
2024-10-05 12:01:50 +00:00
def generate_sprite(main_sprite: Image.Image, expressions: Image.Image, row: int, col: int, configdata: SpritesheetData) -> Image.Image | None:
position, facesize = configdata["position"], configdata["facesize"]
roi = (
2024-10-04 18:18:56 +00:00
col * facesize,
row * facesize,
(col + 1) * facesize - 1,
(row + 1) * facesize - 1
2024-08-09 16:57:33 +00:00
)
2024-10-05 12:01:50 +00:00
expression = expressions.crop(roi)
2024-08-09 16:57:33 +00:00
if is_empty(expression):
return None
2024-10-05 12:01:50 +00:00
composition = main_sprite.copy()
2024-10-04 18:18:56 +00:00
composition.paste(expression, position, expression)
return composition
2024-08-09 16:57:33 +00:00
2024-10-05 12:01:50 +00:00
def save_sprite(image: Image.Image, folder_id: int, name: str, info: tuple | None = None):
savefolder = Paths.OUTPUT / str(folder_id) / name
2024-08-09 16:57:33 +00:00
if not savefolder.is_dir():
savefolder.mkdir()
2024-10-05 12:01:50 +00:00
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 < 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"
2024-08-09 16:57:33 +00:00
with open(outfile, 'wb') as file:
image.save(file)
2024-10-05 12:01:50 +00:00
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:
return True
return False