1
0
Fork 0
mirror of https://github.com/ldericher/fftcgtool synced 2025-01-15 15:02:59 +00:00
fftcgtool/opus.py

158 lines
4.8 KiB
Python

import queue
import threading
import logging
import json
from card import Card, BACKURL
from PIL import Image
# multithreaded card image loading
class imageLoader(threading.Thread):
def __init__(self, queue, composite, composite_lock, grid, resolution):
threading.Thread.__init__(self)
self.__queue = queue
self.__composite = composite
self.__lock = composite_lock
self.__grid = grid
self.__resolution = resolution
def run(self):
logger = logging.getLogger(__name__)
# shorthands
r, c = self.__grid # rows and columns per sheet
w, h = self.__resolution # width, height per card
while not self.__queue.empty():
# take next card
i, card = self.__queue.get()
# fetch card image
logger.info("get image for card {}".format(card))
im = card.get_image(self.__resolution)
# paste image in correct position
self.__lock.acquire()
x, y = (i % c) * w, (i // c) * h
logger.info("paste image {} at P{}({}, {})".format(im.mode, i, x, y))
self.__composite.paste(im, (x, y, x+w, y+h))
self.__lock.release()
# image is processed
self.__queue.task_done()
class Opus:
def __init__(self, data):
self._cards = []
for card_data in data:
card = Card(card_data)
self._cards.append(card)
def __get_sheets(self, grid):
# cards per sheet
count = grid[0]*grid[1] - 1
# flat copy
cards = self._cards
# while there are cards
while cards:
# get a chunk
yield cards[:count]
# remove that chunk
cards = cards[count:]
def get_images(self, grid, resolution, threadnum=16):
logger = logging.getLogger(__name__)
# shorthands
r, c = grid # rows and columns per sheet
w, h = resolution # width, height per card
for sheet in self.__get_sheets(grid):
# enqueue a sheet of cards
cardQueue = queue.Queue()
for i, card in enumerate(sheet):
cardQueue.put((i, card))
# add hidden face
hidden = Card(0)
cardQueue.put((r * c - 1, hidden))
# create a new card sheet
sheet = Image.new("RGB", (c*w, r*h))
logger.info("New image: {}x{}".format(*sheet.size))
# beware concurrent paste
sheet_lock = threading.Lock()
# start multithreading, wait for finish
for _ in range(threadnum):
imageLoader(cardQueue, sheet, sheet_lock, grid, resolution).start()
cardQueue.join()
# sheet image is generated, return now
yield sheet
def get_json(self, opusid, deckname, grid, cardfilter, faceurls):
# shorthands
r, c = grid # rows and columns per sheet
jsondict = { "ObjectStates": [ {
"Name": "Deck",
"Nickname": "Opus {} {}".format(opusid, deckname),
"Description": "",
"Transform": {
"scaleX": 2.17822933,
"scaleY": 1.0,
"scaleZ": 2.17822933
},
"Locked": False,
"Grid": True,
"Snap": True,
"Autoraise": True,
"Sticky": True,
"Tooltip": True,
"GridProjection": False,
"Hands": False,
"SidewaysCard": False,
"DeckIDs": [],
"CustomDeck": {},
"ContainedObjects": []
} ] }
for sheetnum, sheet in enumerate(self.__get_sheets(grid)):
# get current face
faceurl = faceurls[sheetnum]
# first sheet is "CustomDeck 1"
sheetnum = sheetnum + 1
# recurring sheet dictionary
sheetdict = { str(sheetnum): {
"FaceURL": faceurl,
"BackURL": BACKURL,
"NumWidth": c,
"NumHeight": r
} }
for cardnum, card in enumerate(sheet):
if not cardfilter(card):
continue
# cardid 123 is on "CustomDeck 1", 3rd row, 4th column
cardid = sheetnum * 100 + (cardnum // c) * 10 + (cardnum % c) * 1
jsondict["ObjectStates"][0]["DeckIDs"].append(cardid)
# Add card object to ContainedObjects
carddict = card.get_dict()
carddict["CardID"] = cardid
carddict["CustomDeck"] = sheetdict
jsondict["ObjectStates"][0]["ContainedObjects"].append(carddict)
# Add sheet to CustomDecks
jsondict["ObjectStates"][0]["CustomDeck"].update(sheetdict)
return json.dumps(jsondict, indent=2)