Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions LWCProto.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,9 @@ def render_single_cards(
card_matrix = layout.get_single_card_matrix(single_dpi)
ctx.set_matrix(card_matrix)
layout.clip_card(ctx)
ctx.set_source_rgb(1, 1, 1)
ctx.paint()
if card.imageFullFrame:
ctx.set_source_rgb(1, 1, 1)
ctx.paint()

if handle_images and card.imageFullFrame:
_require_image_helpers(load_full_frame_surface_fn)
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ El archivo de definicion de cartas es un archivo en jormato json con el siguente
"text": "str",
"colour": "#RRGGBB"
},
"background_color": "#RRGGBB",
"footer": {
"text": "str",
"color": "#RRGGBB",
Expand All @@ -80,6 +81,7 @@ El archivo de definicion de cartas es un archivo en jormato json con el siguente
```
El objeto `header` define el texto visible en la parte superior de la carta. El campo `color` ajusta el color del texto, mientras que los campos `banner` y `banner_color` permiten activar un recuadro de color sólido detrás del encabezado cuando sea necesario.
El bloque `card_text` permite especificar el texto del cuerpo y el color con el que debe renderizarse. Para las imágenes puedes indicar un nombre de archivo directamente o un objeto con las claves `source` y `full_frame`. Cuando `full_frame_image` (o `full_frame` en el objeto de imagen) es `true`, la ilustración se ampliará para cubrir toda la carta; en caso contrario se mantendrá dentro del marco de arte.
Puedes controlar el color de fondo del lienzo con el campo opcional `background_color`. Debe indicarse en formato hexadecimal (`#RRGGBB`) y solo se aplica cuando la carta no utiliza una imagen a pantalla completa (`full_frame_image: false`).
El bloque `footer` es opcional y permite mostrar una nota en la parte inferior de la carta. Puedes personalizar el texto, su color y el estilo de fuente (`normal`, `negrita` o `itálica`). Si no se especifica `font_style`, se utilizará `normal` por defecto.
Las imagenes deben almacenarse en el directorio "images" que se encuentra en la misma carpeta que LWCProto.py, el formato de las imagenes es indiferente y su tamaño tambien estas seran redimensionadas automaticamente para adaptarse al tamaño disponible en el layout. Puedes utilizar el argumento `--output-dir` para indicar otro directorio base donde almacenar las cartas generadas, lo que facilita mantener varios prototipos separados.

Expand Down
6 changes: 6 additions & 0 deletions card_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def __init__(self, name=None, db=None):
self.footerText = ""
self.footerColour = "#000000"
self.footerFontStyle = "normal"
self.backgroundColour = "#FFFFFF"

if (name is not None) and (db is not None):
# self.load(db[name][0]) For magic AllCards need this index
Expand Down Expand Up @@ -102,6 +103,8 @@ def load(self, data: dict):

self.imageFullFrame = image_full_frame

self.backgroundColour = data.get('background_color', '#FFFFFF') or '#FFFFFF'

footer = data.get('footer') or {}
self.footerText = footer.get('text', '') or ''
self.footerColour = footer.get('color', '#000000') or '#000000'
Expand Down Expand Up @@ -129,6 +132,9 @@ def get_header_banner_color_rgb(self):
def get_footer_text_color_rgb(self):
return self._hex_to_rgb(self.footerColour, default=(0.0, 0.0, 0.0))

def get_background_color_rgb(self):
return self._hex_to_rgb(self.backgroundColour, default=(1.0, 1.0, 1.0))

@staticmethod
def _hex_to_rgb(colour: str, *, default):
value = (colour or '').strip()
Expand Down
2 changes: 2 additions & 0 deletions cartas.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"text": "este es un texto de prueba",
"colour": "#000000"
},
"background_color": "#F5F5F5",
"footer": {
"text": "footer carta 1",
"color": "#333333"
Expand All @@ -32,6 +33,7 @@
"text": "este es un texto de prueba para esta supercarta",
"colour": "#FFFFFF"
},
"background_color": "#002244",
"footer": {
"text": "footer destacado",
"color": "#FFD700",
Expand Down
4 changes: 4 additions & 0 deletions draw_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ def drawCard(
ctx.save()
layout.clip_card(ctx)

if not card.imageFullFrame:
ctx.set_source_rgb(*card.get_background_color_rgb())
ctx.paint()


ctx.select_font_face('serif')

Expand Down
57 changes: 57 additions & 0 deletions tests/test_card_background.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import pytest

try:
import cairo # type: ignore
except Exception: # pragma: no cover - optional dependency missing
cairo = None

from card_model import CardModel

if cairo is not None: # pragma: no branch - conditional import for optional dependency
import layout
from draw_card import drawCard
else: # pragma: no cover - only triggered when cairo is missing
layout = None
drawCard = None


class TrackingCard(CardModel):
def __init__(self):
super().__init__()
self.background_calls = 0

def get_background_color_rgb(self):
self.background_calls += 1
return super().get_background_color_rgb()


def _render_card(card: TrackingCard) -> TrackingCard:
assert cairo is not None and layout is not None and drawCard is not None
dpi = layout.SINGLE_CARD_DPI
surface = layout.get_single_card_surface(dpi)
ctx = cairo.Context(surface)
ctx.set_matrix(layout.get_single_card_matrix(dpi))
drawCard(card, ctx)
return card


@pytest.mark.skipif(cairo is None, reason="pycairo is not available")
def test_draw_card_requests_background_colour_when_not_full_frame():
card = TrackingCard()
card.backgroundColour = '#FF00FF'
card.imageFullFrame = False

rendered = _render_card(card)

assert rendered.background_calls >= 1


@pytest.mark.skipif(cairo is None, reason="pycairo is not available")
def test_draw_card_skips_background_when_full_frame():
card = TrackingCard()
card.backgroundColour = '#FF00FF'
card.imageFullFrame = True

rendered = _render_card(card)

assert rendered.background_calls == 0
5 changes: 5 additions & 0 deletions tests/test_card_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def test_load_with_optional_fields(self):
"toughness": 3,
"image": "wizard.png",
"full_frame_image": True,
"background_color": "#123456",
}

card = CardModel()
Expand All @@ -47,6 +48,8 @@ def test_load_with_optional_fields(self):
self.assertEqual(card.toughness, 3)
self.assertEqual(card.image, "wizard.png")
self.assertTrue(card.imageFullFrame)
self.assertEqual(card.backgroundColour, "#123456")
self.assertEqual(card.get_background_color_rgb(), (0x12 / 255.0, 0x34 / 255.0, 0x56 / 255.0))

def test_load_with_defaults(self):
data = {
Expand Down Expand Up @@ -74,6 +77,8 @@ def test_load_with_defaults(self):
self.assertIsNone(card.toughness)
self.assertIsNone(card.image)
self.assertFalse(card.imageFullFrame)
self.assertEqual(card.backgroundColour, "#FFFFFF")
self.assertEqual(card.get_background_color_rgb(), (1.0, 1.0, 1.0))

def test_load_supports_image_object(self):
data = {
Expand Down