1
0
Fork 0
mirror of https://github.com/ldericher/fftcgtool synced 2025-01-15 15:02:59 +00:00
This commit is contained in:
Jörn-Michael Miehe 2021-08-09 14:03:45 +02:00
parent ac5d05da49
commit a78a3ad04a
4 changed files with 76 additions and 50 deletions

View file

@ -3,70 +3,56 @@ import logging
from PIL import Image from PIL import Image
from .cards import Cards from .cards import Cards
from .grid import Grid
from .imageloader import ImageLoader from .imageloader import ImageLoader
def chunks(whole: list[any], chunk_size) -> list:
# while there are elements
while whole:
# get a chunk
yield whole[:chunk_size]
# remove that chunk
whole = whole[chunk_size:]
class Book: class Book:
# Card faces by Square API
__FACE_URL = "https://fftcg.cdn.sewest.net/images/cards/full/{}_{}.jpg"
# Card back image by Aurik
__BACK_URL = "http://cloud-3.steamusercontent.com/ugc/948455238665576576/85063172B8C340602E8D6C783A457122F53F7843/"
def __init__(self, cards: Cards, grid: tuple[int, int], resolution: tuple[int, int], language: str, def __init__(self, cards: Cards, grid: tuple[int, int], resolution: tuple[int, int], language: str,
num_threads: int): num_threads: int):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# transform grid into Grid
grid = Grid(grid)
# sort cards by element, then alphabetically # sort cards by element, then alphabetically
cards.sort(key=lambda x: x.name) cards.sort(key=lambda x: x.name)
cards.sort(key=lambda x: "Multi" if len(x.elements) > 1 else x.elements[0]) cards.sort(key=lambda x: "Multi" if len(x.elements) > 1 else x.elements[0])
# all card face URLs # all card face URLs
urls = [Book.__FACE_URL.format(card.code, language) for card in cards] urls = [f"https://fftcg.cdn.sewest.net/images/cards/full/{card.code}_{language}.jpg" for card in cards]
# card back URL # card back URL (image by Aurik)
urls.append(Book.__BACK_URL) urls.append(
"http://cloud-3.steamusercontent.com/ugc/948455238665576576/85063172B8C340602E8D6C783A457122F53F7843/"
)
# multithreaded download # multi-threaded download
images = ImageLoader.load(urls, resolution, language, num_threads) images = ImageLoader.load(urls, resolution, language, num_threads)
# card back Image # card back Image
back_image = images.pop(-1) back_image = images.pop(-1)
# shorthands
# rows and columns per sheet
r, c = grid
# capacity of grid (reserve last space for card back)
grid_capacity = r * c - 1
# width, height per card
w, h = resolution
def paste_card(index: int, card: Image) -> None:
x, y = (index % c) * w, (index // c) * h
page.paste(card, (x, y))
self.__pages = [] self.__pages = []
for images in chunks(images, grid_capacity): for page_images, page_cards in zip(grid.chunks(images), grid.chunks(cards)):
# create book page Image # create book page Image
page = Image.new("RGB", (c * w, r * h)) page_image = Image.new("RGB", grid * resolution)
logger.info(f"New image: {page.size[0]}x{page.size[1]}") logger.info(f"New image: {page_image.size[0]}x{page_image.size[1]}")
# paste card faces onto page # paste card faces onto page
for i, image in enumerate(images): for i, image in enumerate(page_images):
paste_card(i, image) grid.paste(page_image, i, image)
# paste card back in last position # paste card back in last position
paste_card(c * r - 1, back_image) grid.paste(page_image, grid.capacity, back_image)
self.__pages.append(page) # save page
self.__pages.append({
"image": page_image,
"cards": page_cards,
})
def __getitem__(self, index: int) -> Image.Image:
return self.__pages[index]["image"]
def save(self, filename: str) -> None: def save(self, filename: str) -> None:
for i, page in enumerate(self.__pages): for i, page in enumerate(self.__pages):
page.save(filename.format(i)) page["image"].save(f"{filename}_{i}.jpg")

33
fftcg/grid.py Normal file
View file

@ -0,0 +1,33 @@
from PIL import Image
class Grid(tuple[int, int]):
def __mul__(self, other):
other = Grid(other)
return Grid((self.x * other.x, self.y * other.y))
@property
def x(self):
return self[0]
@property
def y(self):
return self[1]
@property
def capacity(self):
# capacity of grid (reserve last space for card back)
return self.x * self.y - 1
def chunks(self, whole: list) -> list:
# while there are elements
while whole:
# get a chunk
yield whole[:self.capacity]
# remove that chunk
whole = whole[self.capacity:]
def paste(self, page: Image.Image, index: int, card: Image.Image) -> None:
w, h = card.size
position = (index % self.x) * w, (index // self.x) * h
page.paste(card, position)

View file

@ -10,25 +10,28 @@ class Opus(Cards):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
if opus_id.isnumeric(): if opus_id.isnumeric():
roman_opus_id = roman.toRoman(int(opus_id)) self.__name = f"Opus {roman.toRoman(int(opus_id)).upper()}"
params = {"set": [f"Opus {roman_opus_id.upper()}"]}
self.__number = opus_id self.__number = opus_id
self.__name = f"opus_{opus_id}" self.__filename = f"opus_{opus_id}"
params = {"set": [self.__name]}
elif opus_id == "chaos": elif opus_id == "chaos":
params = {"set": ["Boss Deck Chaos"]} self.__name = "Boss Deck Chaos"
self.__number = "B" self.__number = "B"
self.__name = "boss_deck_chaos" self.__filename = "boss_deck_chaos"
params = {"set": [self.__name]}
elif opus_id == "promo": elif opus_id == "promo":
params = {"rarity": ["pr"]} self.__name = "Promo"
self.__number = "PR" self.__number = "PR"
self.__name = "promo" self.__filename = "promo"
params = {"rarity": ["pr"]}
else: else:
params = {"set": ["?"]}
self.__number = "?"
self.__name = "?" self.__name = "?"
self.__number = "?"
self.__filename = "?"
params = {"set": "?"}
super().__init__(params) super().__init__(params)
@ -51,3 +54,7 @@ class Opus(Cards):
@property @property
def number(self) -> str: def number(self) -> str:
return self.__number return self.__number
@property
def filename(self) -> str:
return self.__filename

View file

@ -6,7 +6,7 @@ import os
import fftcg import fftcg
# constants # constants
GRID = 7, 10 # default in TTsim: 7 rows, 10 columns GRID = 10, 7 # default in TTsim: 10 columns, 7 rows
RESOLUTION = 429, 600 # default in TTsim: 480x670 pixels per card RESOLUTION = 429, 600 # default in TTsim: 480x670 pixels per card
@ -45,7 +45,7 @@ def main() -> None:
# main program # main program
opus = fftcg.Opus(args.opus_id) opus = fftcg.Opus(args.opus_id)
book = fftcg.Book(opus, GRID, RESOLUTION, "eg", args.num_threads) book = fftcg.Book(opus, GRID, RESOLUTION, "eg", args.num_threads)
book.save(f"{opus.name}_{{}}.jpg") book.save(opus.filename)
# bye # bye
logging.info("Done. Put the generated JSON files in your 'Saved Objects' Folder.") logging.info("Done. Put the generated JSON files in your 'Saved Objects' Folder.")