import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from PIL import Image, ImageTk, ImageDraw, ImageFont
import os
import sys

class StudentIDGenerator:
    def __init__(self, root):
        self.root = root
        self.root.title("学生证件生成器")
        self.root.geometry("900x600")
        
        # 变量存储
        self.photo_path = None
        self.photo_image = None  # 用于保持引用，防止被垃圾回收
        self.card_image = None
        
        # 布局配置
        self.setup_ui()
        
    def setup_ui(self):
        # 左侧：输入区域
        left_frame = ttk.Frame(self.root, padding="20")
        left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        ttk.Label(left_frame, text="学生信息录入", font=("Arial", 16, "bold")).pack(pady=(0, 20))
        
        # 表单字段
        fields = [
            ("姓名:", "name"),
            ("学号:", "id_number"),
            ("学院/专业:", "major"),
            ("班级:", "class_name"),
            ("入学年份:", "year")
        ]
        
        self.entries = {}
        for label_text, key in fields:
            frame = ttk.Frame(left_frame)
            frame.pack(fill=tk.X, pady=5)
            ttk.Label(frame, text=label_text, width=12).pack(side=tk.LEFT)
            entry = ttk.Entry(frame)
            entry.pack(side=tk.RIGHT, fill=tk.X, expand=True)
            self.entries[key] = entry
            
        # 默认值填充（方便测试）
        self.entries["name"].insert(0, "张三")
        self.entries["id_number"].insert(0, "2023001001")
        self.entries["major"].insert(0, "计算机科学与技术")
        self.entries["class_name"].insert(0, "23级 1班")
        self.entries["year"].insert(0, "2023")

        # 照片上传按钮
        ttk.Button(left_frame, text="选择证件照", command=self.upload_photo).pack(pady=20, fill=tk.X)
        self.lbl_photo_status = ttk.Label(left_frame, text="未选择照片", foreground="gray")
        self.lbl_photo_status.pack()
        
        # 操作按钮
        btn_frame = ttk.Frame(left_frame)
        btn_frame.pack(pady=30, fill=tk.X)
        ttk.Button(btn_frame, text="生成预览", command=self.generate_card).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="保存图片", command=self.save_card).pack(side=tk.LEFT, padx=5)
        
        # 右侧：预览区域
        right_frame = ttk.Frame(self.root, padding="20", relief=tk.SUNKEN, borderwidth=2)
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        
        ttk.Label(right_frame, text="证件预览", font=("Arial", 16, "bold")).pack(pady=(0, 10))
        
        self.canvas_preview = tk.Canvas(right_frame, bg="#f0f0f0", width=400, height=600)
        self.canvas_preview.pack(fill=tk.BOTH, expand=True)
        
        # 初始化显示提示文字
        self.canvas_preview.create_text(200, 300, text="点击'生成预览'\n查看效果", fill="#888", font=("Arial", 14))

    def upload_photo(self):
        filetypes = [
            ("图片文件", "*.png *.jpg *.jpeg *.bmp"),
            ("所有文件", "*.*")
        ]
        filename = filedialog.askopenfilename(title="选择证件照", filetypes=filetypes)
        if filename:
            self.photo_path = filename
            self.lbl_photo_status.config(text=f"已选择: {os.path.basename(filename)}", foreground="green")

    def get_font(self, size, bold=False):
        # 尝试加载中文字体，否则使用默认
        # Windows 常用: simhei.ttf (黑体), arial.ttf
        # Mac 常用: Heiti TC.ttc
        # Linux: 可能需要安装 wqy-zenhei.ttc
        font_names = ["simhei", "Heiti TC", "wqy-zenhei", "arial"]
        for name in font_names:
            try:
                return ImageFont.truetype(f"{name}.ttc" if "TC" in name else f"{name}.ttf", size)
            except:
                continue
        # 如果都失败，返回默认字体（可能不支持中文显示，会显示方块）
        return ImageFont.load_default()

    def generate_card(self):
        # 获取输入数据
        name = self.entries["name"].get()
        sid = self.entries["id_number"].get()
        major = self.entries["major"].get()
        cls = self.entries["class_name"].get()
        year = self.entries["year"].get()
        
        if not name or not sid:
            messagebox.showwarning("警告", "姓名和学号不能为空！")
            return

        # 创建画布 (标准证件比例，例如 400x600)
        width, height = 400, 600
        card = Image.new('RGB', (width, height), color='white')
        draw = ImageDraw.Draw(card)
        
        # --- 绘制背景设计 ---
        # 顶部蓝色条
        draw.rectangle([0, 0, width, 120], fill="#0056b3")
        # 底部装饰
        draw.rectangle([0, 580, width, 600], fill="#0056b3")
        
        # --- 绘制文字 ---
        font_title = self.get_font(24, bold=True)
        font_label = self.get_font(16)
        font_content = self.get_font(18, bold=True)
        font_small = self.get_font(14)
        
        # 标题
        draw.text((width//2, 40), "学生证 / STUDENT ID", fill="white", font=font_title, anchor="mm")
        
        # 内容区域起始 Y 坐标
        start_y = 280
        
        # 标签和内容
        data = [
            ("姓名", name),
            ("学号", sid),
            ("专业", major),
            ("班级", cls),
            ("入学年份", year)
        ]
        
        current_y = start_y
        for label, value in data:
            # 标签
            draw.text((40, current_y), f"{label}:", fill="#555", font=font_label)
            # 内容
            draw.text((140, current_y), value, fill="#000", font=font_content)
            current_y += 45
            
        # 底部学校名称（模拟）
        draw.text((width//2, 590), "XX 大学 | XX UNIVERSITY", fill="white", font=font_small, anchor="mm")

        # --- 处理照片 ---
        photo_x, photo_y, photo_w, photo_h = 125, 130, 150, 150
        
        # 画一个相框背景
        draw.rectangle([photo_x-5, photo_y-5, photo_x+photo_w+5, photo_y+photo_h+5], fill="#ddd")
        draw.rectangle([photo_x, photo_y, photo_x+photo_w, photo_y+photo_h], fill="white")
        
        if self.photo_path:
            try:
                img = Image.open(self.photo_path)
                # 转换为 RGBA 以处理透明背景
                img = img.convert("RGBA")
                # 裁剪为正方形 (中心裁剪)
                w, h = img.size
                new_size = min(w, h)
                left = (w - new_size) // 2
                top = (h - new_size) // 2
                img = img.crop((left, top, left + new_size, top + new_size))
                # 缩放到相框大小
                img = img.resize((photo_w, photo_h), Image.Resampling.LANCZOS)
                
                # 粘贴到卡片上 (使用 mask 处理透明通道)
                card.paste(img, (photo_x, photo_y), img)
            except Exception as e:
                messagebox.showerror("错误", f"无法加载图片: {e}")
                # 如果出错，画个默认人像图标
                draw.ellipse([photo_x+25, photo_y+20, photo_x+125, photo_y+100], fill="#ccc")
                draw.ellipse([photo_x+25, photo_y+110, photo_x+125, photo_y+150], fill="#ccc")
        else:
            # 没有照片时显示占位符
            draw.text((photo_x + photo_w//2, photo_y + photo_h//2), "无照片", fill="#999", font=font_small, anchor="mm")

        # 更新类变量以便保存
        self.card_image = card
        
        # 在 Tkinter Canvas 上显示
        # 调整大小以适应 Canvas (保持比例)
        display_w = 300
        ratio = display_w / width
        display_h = int(height * ratio)
        card_resized = card.resize((display_w, display_h), Image.Resampling.LANCZOS)
        
        self.tk_photo = ImageTk.PhotoImage(card_resized)
        
        self.canvas_preview.delete("all")
        self.canvas_preview.create_image(200, 300, image=self.tk_photo, anchor="center")
        self.canvas_preview.create_text(200, 15, text="预览模式", fill="#555", font=("Arial", 10))

    def save_card(self):
        if not self.card_image:
            messagebox.showinfo("提示", "请先生成预览再保存！")
            return
            
        file_path = filedialog.asksaveasfilename(
            defaultextension=".png",
            filetypes=[("PNG 文件", "*.png"), ("JPEG 文件", "*.jpg")],
            initialfile=f"{self.entries['name'].get()}_ID.png"
        )
        
        if file_path:
            try:
                # 保存原始分辨率的图片
                self.card_image.save(file_path)
                messagebox.showsuccess("成功", f"证件已保存至:\n{file_path}")
            except Exception as e:
                messagebox.showerror("保存失败", str(e))

# 修复 messagebox.showsuccess (旧版本 tkinter 可能没有)
if not hasattr(messagebox, 'showsuccess'):
    messagebox.showsuccess = lambda title, msg: messagebox.showinfo(title, msg)

if __name__ == "__main__":
    root = tk.Tk()
    # 设置 DPI 感知 (解决高分屏模糊问题)
    try:
        from ctypes import windll
        windll.shcore.SetProcessDpiAwareness(1)
    except:
        pass
        
    app = StudentIDGenerator(root)
    root.mainloop()