"""批量生成邀请函图片:读取 invitation_config.json 模板 + group_members_with_account.csv""" import csv import json import os import sys from PIL import Image, ImageDraw, ImageFont DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "data") BG_PATH = os.path.join(DATA_DIR, "bg.png") FONT_DIR = DATA_DIR CONFIG_PATH = os.path.join(DATA_DIR, "invitation_config.json") CSV_PATH = os.path.join(DATA_DIR, "group_members_with_account.csv") OUTPUT_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "output", "invitations") def hex_to_rgb(h): h = h.lstrip('#') return tuple(int(h[i:i+2], 16) for i in (0, 2, 4)) def resolve_font(name): local = os.path.join(FONT_DIR, name) if os.path.isfile(local): return local sys_font = os.path.join(r"C:\Windows\Fonts", name) if os.path.isfile(sys_font): return sys_font return os.path.join(FONT_DIR, "WenDaoGeTeSong.ttf") def generate_image(cfg, name, account, password): img = Image.open(BG_PATH).copy() draw = ImageDraw.Draw(img) font_path = resolve_font(cfg.get("font", "WenDaoGeTeSong.ttf")) sw = cfg.get("stroke_width", 3) sc = hex_to_rgb(cfg.get("stroke_color", "#000000")) size = cfg.get("size", 30) font = ImageFont.truetype(font_path, size) color = hex_to_rgb(cfg.get("color", "#ffffff")) x = cfg.get("x", 510) y = cfg.get("y", 1055) text = cfg.get("text", "") text = text.replace("{name}", name).replace("{account}", account).replace("{password}", password) line_height = cfg.get("line_height", 1.5) spacing = int(size * (line_height - 1.0)) align = cfg.get("align", "center") anchor_map = {"left": "lt", "center": "mt", "right": "rt"} anchor = anchor_map.get(align, "mt") lines = text.split("\n") cur_y = y for line in lines: draw.text( (x, cur_y), line, fill=color, font=font, anchor=anchor, stroke_width=sw, stroke_fill=sc ) cur_y += size + spacing return img def main(): with open(CONFIG_PATH, encoding="utf-8") as f: cfg = json.load(f) with open(CSV_PATH, encoding="utf-8") as f: rows = list(csv.DictReader(f)) os.makedirs(OUTPUT_DIR, exist_ok=True) total = 0 skipped = 0 for row in rows: name = row.get("姓名", "").strip() account = row.get("账号", "").strip() password = row.get("密码", "").strip() if not account or not password: skipped += 1 continue img = generate_image(cfg, name, account, password) output_path = os.path.join(OUTPUT_DIR, f"invite_{account}.jpg") img.convert("RGB").save(output_path, format="JPEG", quality=75) total += 1 print(f"Done. Generated {total} images, skipped {skipped} (missing account/password).") print(f"Output: {OUTPUT_DIR}") if __name__ == "__main__": main()