From 8050ec3e06c73ca6160ed184362b672a780f1b67 Mon Sep 17 00:00:00 2001 From: Poker Design Developer Date: Wed, 3 Jun 2026 22:18:57 +0800 Subject: [PATCH] feat: use back_design for back rendering in export --- backend/apps/exports/utils.py | 42 +++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/backend/apps/exports/utils.py b/backend/apps/exports/utils.py index b76409d..ebb474a 100644 --- a/backend/apps/exports/utils.py +++ b/backend/apps/exports/utils.py @@ -66,6 +66,15 @@ def get_effective_design(project, card_key): return base +def get_effective_back_design(project): + """获取背面设计配置,合并 back_design 与 card_overrides['back']""" + base = dict(project.back_design or {}) + overrides = (project.card_overrides or {}).get('back', {}) + if overrides: + base.update(overrides) + return base + + def load_image_safe(file_path): """加载图片,找不到时返回 None""" if not file_path: @@ -373,9 +382,13 @@ def draw_joker(canvas, design, which, project, card_key, asset): canvas.alpha_composite(block, (w - tw - 4 - pad, h - 2 * th - 6 - pad)) -def draw_back(canvas, design, asset): - """绘制背面:素材图 + 位置微调,无素材时退化为文字""" +def draw_back(canvas, back_design, asset): + """绘制背面:素材图 + 位置微调 + 色调叠加,无素材时退化为文字""" w, h = canvas.size + # 填充背景色 + bg_color = back_design.get('background_color', '#1A237E') or '#1A237E' + canvas.paste(hex_to_rgba(bg_color, 255), (0, 0, w, h)) + body_pad_x = int(w * 0.15) body_pad_y_top = int(h * 0.18) body_pad_y_bot = int(h * 0.22) @@ -384,9 +397,9 @@ def draw_back(canvas, design, asset): if asset: try: - image_dx = float(design.get('image_dx', 0)) - image_dy = float(design.get('image_dy', 0)) - image_scale = float(design.get('image_scale', 1)) + image_dx = float(back_design.get('image_dx', 0)) + image_dy = float(back_design.get('image_dy', 0)) + image_scale = float(back_design.get('image_scale', 1)) offset_x = int(body_w * image_dx) offset_y = int(body_h * image_dy) @@ -399,13 +412,26 @@ def draw_back(canvas, design, asset): x = body_pad_x + offset_x + (body_w - img.width) // 2 y = body_pad_y_top + offset_y + (body_h - img.height) // 2 canvas.alpha_composite(img, (x, y)) + + # 色调叠加 + pattern_color = back_design.get('pattern_color') + if pattern_color: + tint = Image.new('RGBA', (w, h), hex_to_rgba(pattern_color, 80)) + canvas.alpha_composite(tint) except Exception: pass else: + # 退化:绘制边框 + 文字 + border_color = back_design.get('border_color', '#C0A050') or '#C0A050' draw = ImageDraw.Draw(canvas) + border_width = int(back_design.get('border_width', 3) or 3) + if border_width > 0: + half = max(1, border_width // 2) + draw.rectangle(((half, half), (w - half, h - half)), + outline=hex_to_rgba(border_color, 255), width=border_width) fnt = make_text_font('Times New Roman', max(40, int(h * 0.08)), bold=True) text = 'CARD BACK' - color = hex_to_rgba(design.get('border_color', '#333333'), 255) + color = hex_to_rgba(border_color, 255) bb = draw.textbbox((0, 0), text, font=fnt) tw, th = bb[2] - bb[0], bb[3] - bb[1] draw.text(((w - tw) // 2, (h - th) // 2), text, font=fnt, fill=color) @@ -439,12 +465,14 @@ def generate_card_png(project, card_key, resolution='standard'): break draw_joker(canvas, design, which, project, card_key, asset) elif card_key in ('back', 'card-back'): + back_design = get_effective_back_design(project) back_asset = None for a in project.assets.filter(asset_type='back'): p = os.path.join('media', a.file_path) if a.file_path else None back_asset = load_image_safe(p) if p else None break - draw_back(canvas, design, back_asset) + draw_back(canvas, back_design, back_asset) + return canvas else: # 'suit-rank' parts = card_key.split('-')