feat: daily collection 6/12 - new docs, industry report, .gitignore cleanup
- Collected 9 new messages from dc group and innovation group - Fetched 6 new Feishu docs (黄静雯/陈楚真/韦译/夏莲/莫润麟/张家振) - Downloaded 狱国争霸分析拆解.html file attachment - Saved 6/12 game industry daily report from 韩丹 - Updated .gitignore to exclude temp scripts, images, downloaded files - Added utility scripts (group members extraction, invitation generation)
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
"""批量生成邀请函图片:读取 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()
|
||||
Reference in New Issue
Block a user