From 36e754557f2bef9956d685330cb467fe17b57b9d Mon Sep 17 00:00:00 2001 From: Gregory Marco Date: Sun, 13 Jul 2025 00:24:34 -0500 Subject: [PATCH] Add initial support for drawing symbols onto card frame. --- yagicard/__init__.py | 68 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/yagicard/__init__.py b/yagicard/__init__.py index 7fe0939..f437244 100755 --- a/yagicard/__init__.py +++ b/yagicard/__init__.py @@ -10,7 +10,8 @@ from goat import util FRAMES_DIRECTORY = "frames" 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_FONT = "EBGaramond-Regular.ttf" @@ -19,6 +20,33 @@ DEFAULT_FONT_SIZE = 12 NAME_FONT = "Electrolize-Regular.ttf" 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 (): def __init__ (self, style_rules, value, card): self.style_rules = style_rules @@ -47,7 +75,7 @@ def resolve_style_rule (rule, *args): def load_font (name, size): for directory in FONTS_DIRECTORIES: try: - return ImageFont.truetype(os.path.join(directory, name), size) + return ImageFont.truetype(os.path.join(base_directory, directory, name), size) except OSError: pass raise OSError("failed to open font: " + name) @@ -55,23 +83,24 @@ def load_font (name, size): def draw_text (image, draw, field): if not (field.has("y") and field.has("x")): return - + color = field.get("color", DEFAULT_TEXT_COLOR) font_size = field.get("size", DEFAULT_FONT_SIZE) font_name = field.get("typeface", DEFAULT_FONT) text_anchor = field.get("anchor", None) alignment = field.get("align", "left") + direction = field.get("direction", "ltr") font = load_font(font_name, font_size) font_variant = field.get("font_variant") if 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): - source_image = Image.open(os.path.join(IMAGES_DIRECTORY, field.value)) - + source_image = images[field.value] + width = field.get("width") height = field.get("height") @@ -80,6 +109,30 @@ def draw_image (image, draw, field): 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 scaler (value): for arg in args: @@ -211,6 +264,7 @@ def main(): yagicardfile = os.path.join(yagicard_root, YAGICARDFILE) with open(yagicardfile) as yagicardcode: + base_directory = yagicard_root namespace = { "YAGICARD_ROOT": yagicard_root }