import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import numpy as np

# 标准颜色库
COLOR_NAMES = {
    (255, 0, 0): "红色", (0, 255, 0): "绿色", (0, 0, 255): "蓝色",
    (255, 255, 0): "黄色", (255, 0, 255): "品红", (0, 255, 255): "青色",
    (0, 0, 0): "黑色", (255, 255, 255): "白色", (128, 128, 128): "灰色",
    (128, 0, 0): "暗红", (0, 128, 0): "深绿", (0, 0, 128): "深蓝",
    (255, 165, 0): "橙色", (255, 192, 203): "粉色", (160, 82, 45): "棕色"
}

class ColorPickerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("图片颜色识别工具")
        self.root.geometry("900x700")

        self.cv_img = None
        self.pil_img = None
        self.tk_img = None
        self.img_w, self.img_h = 0, 0
        self.display_w, self.display_h = 0, 0  # 窗口里显示的图片尺寸

        # 顶部按钮区
        top_frame = tk.Frame(root)
        top_frame.pack(fill=tk.X, padx=10, pady=5)
        tk.Button(top_frame, text="打开图片", command=self.load_image, width=10).pack(side=tk.LEFT, padx=5)
        tk.Button(top_frame, text="复制HEX", command=self.copy_hex, width=8).pack(side=tk.LEFT, padx=5)
        tk.Button(top_frame, text="复制RGB", command=self.copy_rgb, width=8).pack(side=tk.LEFT, padx=5)
        self.info_label = tk.Label(top_frame, text="请点击【打开图片】选择文件", fg="#555")
        self.info_label.pack(side=tk.LEFT, padx=20)

        # 画布
        self.canvas = tk.Canvas(root, bg="#eeeeee")
        self.canvas.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        self.canvas.bind("<Button-1>", self.pick_color)

        # 底部信息栏
        bottom_frame = tk.Frame(root, height=120, bg="#f0f0f0")
        bottom_frame.pack(fill=tk.X, padx=10, pady=5)

        self.color_box = tk.Label(bottom_frame, bg="white", width=10, height=5, relief=tk.SUNKEN)
        self.color_box.pack(side=tk.LEFT, padx=10, pady=10)

        info_inner = tk.Frame(bottom_frame)
        info_inner.pack(side=tk.LEFT)
        self.rgb_text = tk.Label(info_inner, text="RGB: -- , -- , --", font=("微软雅黑", 11))
        self.rgb_text.pack(anchor="w")
        self.hex_text = tk.Label(info_inner, text="HEX: #------", font=("微软雅黑", 11))
        self.hex_text.pack(anchor="w")
        self.name_text = tk.Label(info_inner, text="颜色名称: 未选取", font=("微软雅黑", 11))
        self.name_text.pack(anchor="w")

        # 缓存当前颜色值
        self.now_rgb = (0, 0, 0)
        self.now_hex = "#000000"

    def load_image(self):
        path = filedialog.askopenfilename(
            title="选择图片",
            filetypes=[("图片文件", "*.jpg;*.jpeg;*.png;*.bmp"), ("所有文件", "*.*")]
        )
        if not path:
            return
        try:
            raw = cv2.imread(path)
            self.cv_img = cv2.cvtColor(raw, cv2.COLOR_BGR2RGB)
            self.img_h, self.img_w = self.cv_img.shape[:2]
            self.pil_img = Image.fromarray(self.cv_img)

            # 获取画布真实大小
            self.root.update()
            cw = self.canvas.winfo_width() - 20
            ch = self.canvas.winfo_height() - 20
            # 缩放图片
            self.pil_img.thumbnail((cw, ch))
            self.display_w, self.display_h = self.pil_img.size
            self.tk_img = ImageTk.PhotoImage(self.pil_img)

            self.canvas.delete("all")
            self.canvas.create_image(cw//2 + 10, ch//2 + 10, image=self.tk_img, anchor=tk.CENTER)
            self.info_label.config(text=f"已加载: {path.split('/')[-1]}")
        except Exception as e:
            messagebox.showerror("错误", f"图片加载失败：{str(e)}")

    def get_closest_color_name(self, r, g, b):
        min_dist = float("inf")
        name = "未知颜色"
        for (cr, cg, cb), n in COLOR_NAMES.items():
            dist = np.sqrt((r - cr)**2 + (g - cg)**2 + (b - cb)**2)
            if dist < min_dist:
                min_dist = dist
                name = n
        return name

    def pick_color(self, event):
        if self.cv_img is None:
            messagebox.showwarning("提示", "先载入图片！")
            return
        # 修正坐标映射
        rate_x = self.img_w / self.display_w
        rate_y = self.img_h / self.display_h
        real_x = int((event.x - self.canvas.winfo_x()) * rate_x)
        real_y = int((event.y - self.canvas.winfo_y()) * rate_y)

        if 0 <= real_x < self.img_w and 0 <= real_y < self.img_h:
            r, g, b = self.cv_img[real_y, real_x]
            self.now_rgb = (r, g, b)
            self.now_hex = f"#{r:02X}{g:02X}{b:02X}"
            c_name = self.get_closest_color_name(r, g, b)

            self.color_box.config(bg=self.now_hex)
            self.rgb_text.config(text=f"RGB: {r} , {g} , {b}")
            self.hex_text.config(text=f"HEX: {self.now_hex}")
            self.name_text.config(text=f"颜色名称: {c_name}")

    def copy_hex(self):
        self.root.clipboard_clear()
        self.root.clipboard_append(self.now_hex)
        messagebox.showinfo("提示", "HEX色值已复制到剪贴板")

    def copy_rgb(self):
        r, g, b = self.now_rgb
        txt = f"{r},{g},{b}"
        self.root.clipboard_clear()
        self.root.clipboard_append(txt)
        messagebox.showinfo("提示", "RGB数值已复制到剪贴板")

if __name__ == "__main__":
    root = tk.Tk()
    app = ColorPickerGUI(root)
    root.mainloop()