|
@@ -355,9 +355,34 @@ NUMBER_DISPLAY = {
|
|
|
"King": "K",
|
|
|
}
|
|
|
|
|
|
+MAJOR_DISPLAY = {
|
|
|
+ "0.": "\U0001f0e0",
|
|
|
+ "I.": "\U0001f0e1",
|
|
|
+ "II.": "\U0001f0e2",
|
|
|
+ "III.": "\U0001f0e3",
|
|
|
+ "IV.": "\U0001f0e4",
|
|
|
+ "V.": "\U0001f0e5",
|
|
|
+ "VI.": "\U0001f0e6",
|
|
|
+ "VII.": "\U0001f0e7",
|
|
|
+ "VIII.": "\U0001f0e8",
|
|
|
+ "IX.": "\U0001f0e9",
|
|
|
+ "X.": "\U0001f0ea",
|
|
|
+ "XI.": "\U0001f0eb",
|
|
|
+ "XII.": "\U0001f0ec",
|
|
|
+ "XIII.": "\U0001f0ed",
|
|
|
+ "XIV.": "\U0001f0ee",
|
|
|
+ "XV.": "\U0001f0ef",
|
|
|
+ "XVI.": "\U0001f0f0",
|
|
|
+ "XVII.": "\U0001f0f1",
|
|
|
+ "XVIII.": "\U0001f0f2",
|
|
|
+ "XIX.": "\U0001f0f3",
|
|
|
+ "XX.": "\U0001f0f4",
|
|
|
+ "XXI.": "\U0001f0f5",
|
|
|
+}
|
|
|
+
|
|
|
CARD_W = 800
|
|
|
-# cards are 2x3
|
|
|
-CARD_H = 3 * CARD_W // 2
|
|
|
+# aspect ratio determined by rigorous testing
|
|
|
+CARD_H = 31 * CARD_W // 25
|
|
|
# spacing of 1/8 the width
|
|
|
CARD_GAP = CARD_W // 8
|
|
|
CARD_WG = CARD_W + 2 * CARD_GAP
|
|
@@ -370,10 +395,15 @@ CARD_BORDER = CARD_W // 32
|
|
|
|
|
|
# https://fonts.google.com/specimen/Lumanosimo
|
|
|
FONT_SIZE = CARD_W // 4
|
|
|
-FONT = ImageFont.truetype(
|
|
|
+TITLE_FONT = ImageFont.truetype(
|
|
|
os.path.join(os.path.dirname(os.path.realpath(__file__)), "Lumanosimo.ttf"),
|
|
|
FONT_SIZE,
|
|
|
)
|
|
|
+# https://www.fontspace.com/symbola-font-f22021
|
|
|
+SYMBOL_FONT = ImageFont.truetype(
|
|
|
+ os.path.join(os.path.dirname(os.path.realpath(__file__)), "Symbola.ttf"),
|
|
|
+ CARD_H - (CARD_BORDER * 2),
|
|
|
+)
|
|
|
|
|
|
SUIT_LINE = {
|
|
|
k: [(int(x * CARD_W / 10), int(y * CARD_H / 10)) for x, y in v]
|
|
@@ -423,18 +453,6 @@ SUIT_LINE = {
|
|
|
],
|
|
|
}.items()
|
|
|
}
|
|
|
-SPECIAL_LINE = [
|
|
|
- (int(x * CARD_W / 10), int(y * CARD_H / 10))
|
|
|
- for x, y in [
|
|
|
- (6, 5),
|
|
|
- (8, 6),
|
|
|
- (8, 7.5),
|
|
|
- (6, 8.5),
|
|
|
- (4, 7.5),
|
|
|
- (4, 6),
|
|
|
- (6, 5),
|
|
|
- ]
|
|
|
-]
|
|
|
|
|
|
|
|
|
@as_command
|
|
@@ -473,32 +491,42 @@ def tarot(
|
|
|
width=CARD_BORDER,
|
|
|
fill=(71, 6, 47, 255),
|
|
|
)
|
|
|
- draw.text(
|
|
|
- xy=(CARD_TEXT_OFF, CARD_TEXT_OFF),
|
|
|
- text=NUMBER_DISPLAY.get(p1, p1),
|
|
|
- fill=HIGHLIGHT,
|
|
|
- font=FONT,
|
|
|
- stroke_width=FONT_SIZE // 6,
|
|
|
- )
|
|
|
- draw.text(
|
|
|
- xy=(CARD_TEXT_OFF, CARD_TEXT_OFF),
|
|
|
- text=NUMBER_DISPLAY.get(p1, p1),
|
|
|
- fill=SUIT_COLOR.get(p2, (0, 0, 0, 0)),
|
|
|
- font=FONT,
|
|
|
- )
|
|
|
- draw.line(
|
|
|
- xy=SUIT_LINE.get(p2, SPECIAL_LINE),
|
|
|
- fill=SUIT_COLOR.get(p2, HIGHLIGHT),
|
|
|
- width=CARD_BORDER,
|
|
|
- joint="curve",
|
|
|
- )
|
|
|
+ if (xy := SUIT_LINE.get(p2)) is not None:
|
|
|
+ draw.line(
|
|
|
+ xy=xy,
|
|
|
+ fill=SUIT_COLOR.get(p2, HIGHLIGHT),
|
|
|
+ width=CARD_BORDER,
|
|
|
+ joint="curve",
|
|
|
+ )
|
|
|
+ draw.text(
|
|
|
+ xy=(CARD_TEXT_OFF, CARD_TEXT_OFF),
|
|
|
+ text=NUMBER_DISPLAY.get(p1, p1),
|
|
|
+ fill=HIGHLIGHT,
|
|
|
+ font=TITLE_FONT,
|
|
|
+ stroke_width=FONT_SIZE // 6,
|
|
|
+ )
|
|
|
+ draw.text(
|
|
|
+ xy=(CARD_TEXT_OFF, CARD_TEXT_OFF),
|
|
|
+ text=NUMBER_DISPLAY.get(p1, p1),
|
|
|
+ fill=SUIT_COLOR.get(p2, (0, 0, 0, 0)),
|
|
|
+ font=TITLE_FONT,
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ draw.text(
|
|
|
+ xy=(CARD_BORDER, CARD_BORDER),
|
|
|
+ text=MAJOR_DISPLAY.get(p1, p1),
|
|
|
+ fill=HIGHLIGHT,
|
|
|
+ font=SYMBOL_FONT,
|
|
|
+ )
|
|
|
card_images.append(image if face == 0 else image.rotate(180))
|
|
|
|
|
|
with Image.new(
|
|
|
"RGBA", (len(card_images) * CARD_WG, CARD_H + CARD_OFF), color=(0, 0, 0, 0)
|
|
|
) as image:
|
|
|
for i, card_img in enumerate(card_images):
|
|
|
- image.paste(card_img, (i * (CARD_W + CARD_GAP) + CARD_GAP, ((i + 1) % 2) * CARD_OFF))
|
|
|
+ image.paste(
|
|
|
+ card_img, (i * (CARD_W + CARD_GAP) + CARD_GAP, ((i + 1) % 2) * CARD_OFF)
|
|
|
+ )
|
|
|
with BytesIO() as buf:
|
|
|
image.save(buf, "PNG")
|
|
|
att = Attachment(name="image", body=buf.getvalue())
|