Add initial support for drawing symbols onto card frame.

This commit is contained in:
2025-07-13 00:24:34 -05:00
parent bab3e08627
commit 36e754557f

View File

@@ -11,6 +11,7 @@ FRAMES_DIRECTORY = "frames"
FONTS_DIRECTORIES = [".", "fonts", os.path.join(os.environ.get("HOME", ""), ".fonts")] FONTS_DIRECTORIES = [".", "fonts", os.path.join(os.environ.get("HOME", ""), ".fonts")]
IMAGES_DIRECTORY = "images" IMAGES_DIRECTORY = "images"
SYMBOLS_DIRECTORY = "symbols"
DEFAULT_TEXT_COLOR = "black" DEFAULT_TEXT_COLOR = "black"
DEFAULT_FONT = "EBGaramond-Regular.ttf" DEFAULT_FONT = "EBGaramond-Regular.ttf"
@@ -19,6 +20,33 @@ DEFAULT_FONT_SIZE = 12
NAME_FONT = "Electrolize-Regular.ttf" NAME_FONT = "Electrolize-Regular.ttf"
YAGICARDFILE = "Yagicardfile" YAGICARDFILE = "Yagicardfile"
base_directory = "."
class Images ():
def __init__ (self, directory):
self.directory = directory
self.images = {}
def __getitem__ (self, key):
if key in self.images:
return self.images[key]
if os.path.splitext(key)[1] == "":
key = f"{key}.png"
if key in self.images:
return self.images[key]
image = Image.open(os.path.join(base_directory, self.directory, key))
self.images[key] = image
return image
def __setitem__ (self, key, value):
self.images[key] = value
images = Images(IMAGES_DIRECTORY)
symbols = Images(SYMBOLS_DIRECTORY)
class Field (): class Field ():
def __init__ (self, style_rules, value, card): def __init__ (self, style_rules, value, card):
self.style_rules = style_rules self.style_rules = style_rules
@@ -47,7 +75,7 @@ def resolve_style_rule (rule, *args):
def load_font (name, size): def load_font (name, size):
for directory in FONTS_DIRECTORIES: for directory in FONTS_DIRECTORIES:
try: try:
return ImageFont.truetype(os.path.join(directory, name), size) return ImageFont.truetype(os.path.join(base_directory, directory, name), size)
except OSError: pass except OSError: pass
raise OSError("failed to open font: " + name) raise OSError("failed to open font: " + name)
@@ -61,16 +89,17 @@ def draw_text (image, draw, field):
font_name = field.get("typeface", DEFAULT_FONT) font_name = field.get("typeface", DEFAULT_FONT)
text_anchor = field.get("anchor", None) text_anchor = field.get("anchor", None)
alignment = field.get("align", "left") alignment = field.get("align", "left")
direction = field.get("direction", "ltr")
font = load_font(font_name, font_size) font = load_font(font_name, font_size)
font_variant = field.get("font_variant") font_variant = field.get("font_variant")
if font_variant: if font_variant:
font.set_variation_by_name(font_variant) font.set_variation_by_name(font_variant)
draw.multiline_text((field.get("x"), field.get("y")), field.value, font=font, fill=color, anchor=text_anchor, align=alignment) draw.multiline_text((field.get("x"), field.get("y")), field.value, font=font, fill=color, anchor=text_anchor, align=alignment) #, direction=direction)
def draw_image (image, draw, field): def draw_image (image, draw, field):
source_image = Image.open(os.path.join(IMAGES_DIRECTORY, field.value)) source_image = images[field.value]
width = field.get("width") width = field.get("width")
height = field.get("height") height = field.get("height")
@@ -80,6 +109,30 @@ def draw_image (image, draw, field):
image.paste(source_image, (field.get("x"), field.get("y"))) image.paste(source_image, (field.get("x"), field.get("y")))
def draw_symbols (image, draw, field):
symbol_text = field.value.lower()
if symbol_text.startswith("{") and symbol_text.endswith("}"):
symbol_text = symbol_text[1:-1].replace("}{", " ")
width = field.get("width", image.width)
height = field.get("height", image.height)
direction = field.get("direction", "ltr")
symbols_image = Image.new(image.mode, (width, height))
symbol_pos = (0, 0)
for symbol_name in symbol_text.split(" "):
if symbol_name:
symbol = symbols[symbol_name]
symbols_image.paste(symbol, symbol_pos)
if direction == "ltr":
symbol_pos = (symbol_pos[0] + symbol.width, symbol_pos[1])
elif direction == "ttb":
symbol_pos = (symbol_pos[0], symbol_pos[1] + symbol.height)
image.alpha_composite(symbols_image, (field.get("x"), field.get("y")))
def rescale_text_for_sizes (*args): def rescale_text_for_sizes (*args):
def scaler (value): def scaler (value):
for arg in args: for arg in args:
@@ -211,6 +264,7 @@ def main():
yagicardfile = os.path.join(yagicard_root, YAGICARDFILE) yagicardfile = os.path.join(yagicard_root, YAGICARDFILE)
with open(yagicardfile) as yagicardcode: with open(yagicardfile) as yagicardcode:
base_directory = yagicard_root
namespace = { namespace = {
"YAGICARD_ROOT": yagicard_root "YAGICARD_ROOT": yagicard_root
} }