import tkinter as tk
from tkinter import ttk, filedialog, messagebox, colorchooser
from PIL import Image, ImageTk, ImageDraw
import colorsys
import webcolors
import os

class ColorIdentifier:
    def __init__(self, root):
        self.root = root
        self.root.title("🎨 颜色识别器")
        self.root.geometry("1000x700")
        self.root.resizable(True, True)
        
        # 颜色数据
        self.common_colors = {
            '红色': '#FF0000',
            '橙色': '#FF8C00',
            '黄色': '#FFD700',
            '绿色': '#00FF00',
            '青色': '#00FFFF',
            '蓝色': '#0000FF',
            '紫色': '#8B00FF',
            '粉色': '#FF69B4',
            '棕色': '#8B4513',
            '黑色': '#000000',
            '白色': '#FFFFFF',
            '灰色': '#808080',
            '金色': '#FFD700',
            '银色': '#C0C0C0',
            '玫红': '#FF007F',
            '天蓝': '#87CEEB',
            '草绿': '#7CFC00',
            '橄榄': '#808000',
            '深蓝': '#000080',
            '紫红': '#800080'
        }
        
        # 当前颜色
        self.current_color = '#FF0000'
        self.current_rgb = (255, 0, 0)
        self.current_hsv = (0, 1, 1)
        
        # 图片相关
        self.image = None
        self.image_tk = None
        self.zoom_factor = 1.0
        self.pixel_info = None
        
        # 创建界面
        self.create_widgets()
        
        # 更新颜色显示
        self.update_color_display()
        
    def create_widgets(self):
        """创建界面组件"""
        # 主框架
        main_frame = tk.Frame(self.root, bg='#f0f0f0')
        main_frame.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 左侧：图片和工具
        left_frame = tk.Frame(main_frame, bg='#f0f0f0')
        left_frame.pack(side='left', fill='both', expand=True)
        
        # 工具栏
        tool_frame = tk.Frame(left_frame, bg='#e0e0e0', relief='ridge', bd=2)
        tool_frame.pack(fill='x', pady=(0, 10))
        
        # 打开图片按钮
        open_btn = tk.Button(
            tool_frame,
            text="📁 打开图片",
            command=self.open_image,
            font=('微软雅黑', 12),
            bg='#4CAF50',
            fg='white',
            padx=20,
            pady=8,
            cursor='hand2'
        )
        open_btn.pack(side='left', padx=5, pady=5)
        
        # 相机按钮
        camera_btn = tk.Button(
            tool_frame,
            text="📷 相机取色",
            command=self.open_camera,
            font=('微软雅黑', 12),
            bg='#2196F3',
            fg='white',
            padx=20,
            pady=8,
            cursor='hand2'
        )
        camera_btn.pack(side='left', padx=5, pady=5)
        
        # 选择颜色按钮
        picker_btn = tk.Button(
            tool_frame,
            text="🎨 颜色选择器",
            command=self.open_color_picker,
            font=('微软雅黑', 12),
            bg='#FF9800',
            fg='white',
            padx=20,
            pady=8,
            cursor='hand2'
        )
        picker_btn.pack(side='left', padx=5, pady=5)
        
        # 放大缩小
        zoom_frame = tk.Frame(tool_frame, bg='#e0e0e0')
        zoom_frame.pack(side='right', padx=5, pady=5)
        
        tk.Label(zoom_frame, text="缩放：", font=('微软雅黑', 10),
                bg='#e0e0e0').pack(side='left')
        
        zoom_out_btn = tk.Button(
            zoom_frame,
            text="➖",
            command=lambda: self.zoom_image(0.8),
            font=('微软雅黑', 12),
            width=3
        )
        zoom_out_btn.pack(side='left', padx=2)
        
        self.zoom_label = tk.Label(zoom_frame, text="100%", 
                                   font=('微软雅黑', 10), bg='#e0e0e0')
        self.zoom_label.pack(side='left', padx=5)
        
        zoom_in_btn = tk.Button(
            zoom_frame,
            text="➕",
            command=lambda: self.zoom_image(1.25),
            font=('微软雅黑', 12),
            width=3
        )
        zoom_in_btn.pack(side='left', padx=2)
        
        # 图片显示区域
        self.image_frame = tk.Frame(left_frame, bg='white', relief='ridge', bd=2)
        self.image_frame.pack(fill='both', expand=True)
        
        self.canvas = tk.Canvas(
            self.image_frame,
            bg='white',
            cursor='crosshair'
        )
        self.canvas.pack(fill='both', expand=True)
        
        # 绑定鼠标事件
        self.canvas.bind('<Motion>', self.on_mouse_move)
        self.canvas.bind('<Button-1>', self.on_mouse_click)
        
        # 右侧：颜色信息
        right_frame = tk.Frame(main_frame, bg='#f0f0f0', width=350)
        right_frame.pack(side='right', fill='both', padx=(10, 0))
        right_frame.pack_propagate(False)
        
        # 颜色显示
        self.color_display = tk.Label(
            right_frame,
            text="当前颜色",
            font=('微软雅黑', 14, 'bold'),
            bg='#FF0000',
            fg='white',
            height=4,
            relief='ridge'
        )
        self.color_display.pack(fill='x', pady=(0, 10))
        
        # 颜色代码
        code_frame = tk.Frame(right_frame, bg='#f0f0f0')
        code_frame.pack(fill='x', pady=5)
        
        tk.Label(code_frame, text="HEX: ", font=('微软雅黑', 12),
                bg='#f0f0f0').pack(side='left')
        self.hex_label = tk.Label(code_frame, text="#FF0000", 
                                  font=('微软雅黑', 12, 'bold'),
                                  bg='#f0f0f0', fg='#333')
        self.hex_label.pack(side='left')
        
        # 复制按钮
        copy_btn = tk.Button(
            code_frame,
            text="📋 复制",
            command=self.copy_color,
            font=('微软雅黑', 9),
            bg='#607D8B',
            fg='white',
            padx=10,
            cursor='hand2'
        )
        copy_btn.pack(side='right')
        
        # RGB值
        rgb_frame = tk.Frame(right_frame, bg='#f0f0f0')
        rgb_frame.pack(fill='x', pady=5)
        
        tk.Label(rgb_frame, text="RGB: ", font=('微软雅黑', 12),
                bg='#f0f0f0').pack(side='left')
        self.rgb_label = tk.Label(rgb_frame, text="(255, 0, 0)",
                                  font=('微软雅黑', 12),
                                  bg='#f0f0f0', fg='#333')
        self.rgb_label.pack(side='left')
        
        # HSV值
        hsv_frame = tk.Frame(right_frame, bg='#f0f0f0')
        hsv_frame.pack(fill='x', pady=5)
        
        tk.Label(hsv_frame, text="HSV: ", font=('微软雅黑', 12),
                bg='#f0f0f0').pack(side='left')
        self.hsv_label = tk.Label(hsv_frame, text="(0, 100%, 100%)",
                                  font=('微软雅黑', 12),
                                  bg='#f0f0f0', fg='#333')
        self.hsv_label.pack(side='left')
        
        # 颜色名称
        name_frame = tk.Frame(right_frame, bg='#f0f0f0')
        name_frame.pack(fill='x', pady=5)
        
        tk.Label(name_frame, text="颜色名称: ", font=('微软雅黑', 12),
                bg='#f0f0f0').pack(side='left')
        self.name_label = tk.Label(name_frame, text="红色",
                                   font=('微软雅黑', 12, 'bold'),
                                   bg='#f0f0f0', fg='#e74c3c')
        self.name_label.pack(side='left')
        
        # 颜色相似度
        sim_frame = tk.Frame(right_frame, bg='#f0f0f0')
        sim_frame.pack(fill='x', pady=5)
        
        tk.Label(sim_frame, text="相似颜色: ", font=('微软雅黑', 12),
                bg='#f0f0f0').pack(side='left')
        self.sim_label = tk.Label(sim_frame, text="",
                                  font=('微软雅黑', 10),
                                  bg='#f0f0f0', fg='#666')
        self.sim_label.pack(side='left')
        
        # 分离线
        ttk.Separator(right_frame, orient='horizontal').pack(fill='x', pady=10)
        
        # 颜色历史
        history_frame = tk.Frame(right_frame, bg='#f0f0f0')
        history_frame.pack(fill='both', expand=True)
        
        tk.Label(history_frame, text="📊 颜色历史", font=('微软雅黑', 12, 'bold'),
                bg='#f0f0f0').pack(anchor='w')
        
        self.history_canvas = tk.Canvas(
            history_frame,
            bg='#f0f0f0',
            height=100
        )
        self.history_canvas.pack(fill='x', pady=5)
        
        # 颜色信息
        info_text = tk.Text(right_frame, height=8, font=('微软雅黑', 10),
                           bg='#fafafa', wrap='word')
        info_text.pack(fill='both', expand=True, pady=5)
        info_text.insert('1.0', 
            "📖 使用说明：\n"
            "1. 点击「打开图片」加载图片\n"
            "2. 鼠标在图片上移动查看颜色\n"
            "3. 点击图片固定颜色\n"
            "4. 使用「颜色选择器」手动选色\n"
            "5. 使用「相机取色」实时取色\n"
            "6. 点击「复制」复制颜色代码\n"
        )
        info_text.config(state='disabled')
        
        # 颜色历史
        self.color_history = []
        self.max_history = 10
        
        # 默认显示
        self.show_default_image()
        
    def show_default_image(self):
        """显示默认颜色示例"""
        self.canvas.delete('all')
        # 绘制渐变色示例
        width = 600
        height = 400
        image = Image.new('RGB', (width, height), 'white')
        draw = ImageDraw.Draw(image)
        
        # 绘制彩虹渐变色
        for x in range(width):
            hue = x / width
            rgb = colorsys.hsv_to_rgb(hue, 1, 1)
            r = int(rgb[0] * 255)
            g = int(rgb[1] * 255)
            b = int(rgb[2] * 255)
            draw.line([(x, 0), (x, height)], fill=(r, g, b))
        
        self.image_tk = ImageTk.PhotoImage(image)
        self.canvas.create_image(0, 0, anchor='nw', image=self.image_tk)
        self.canvas.config(scrollregion=self.canvas.bbox('all'))
        
    def open_image(self):
        """打开图片"""
        file_path = filedialog.askopenfilename(
            title="选择图片",
            filetypes=[
                ("图片文件", "*.png *.jpg *.jpeg *.bmp *.gif *.tiff"),
                ("所有文件", "*.*")
            ]
        )
        
        if file_path:
            try:
                self.image = Image.open(file_path)
                self.zoom_factor = 1.0
                self.display_image()
                messagebox.showinfo("成功", f"已加载图片：{os.path.basename(file_path)}")
            except Exception as e:
                messagebox.showerror("错误", f"无法加载图片：{str(e)}")
    
    def display_image(self):
        """显示图片"""
        if not self.image:
            return
        
        # 计算缩放后的尺寸
        width = int(self.image.width * self.zoom_factor)
        height = int(self.image.height * self.zoom_factor)
        
        # 缩放图片
        resized_image = self.image.resize((width, height), Image.Resampling.LANCZOS)
        self.image_tk = ImageTk.PhotoImage(resized_image)
        
        # 更新画布
        self.canvas.delete('all')
        self.canvas.create_image(0, 0, anchor='nw', image=self.image_tk)
        self.canvas.config(scrollregion=self.canvas.bbox('all'))
        self.canvas.config(width=width, height=height)
        
        # 更新缩放标签
        self.zoom_label.config(text=f"{int(self.zoom_factor * 100)}%")
    
    def zoom_image(self, factor):
        """缩放图片"""
        if not self.image:
            return
        
        new_zoom = self.zoom_factor * factor
        if 0.1 <= new_zoom <= 5.0:
            self.zoom_factor = new_zoom
            self.display_image()
    
    def on_mouse_move(self, event):
        """鼠标移动事件"""
        if not self.image:
            return
        
        # 获取鼠标在图片上的位置
        x = event.x
        y = event.y
        
        # 转换为实际图片坐标
        real_x = int(x / self.zoom_factor)
        real_y = int(y / self.zoom_factor)
        
        if 0 <= real_x < self.image.width and 0 <= real_y < self.image.height:
            # 获取像素颜色
            pixel = self.image.getpixel((real_x, real_y))
            if len(pixel) == 4:  # RGBA
                pixel = pixel[:3]
            self.update_color_info(pixel)
            
            # 显示坐标
            self.canvas.delete('coords')
            self.canvas.create_text(
                x + 10, y - 10,
                text=f"({real_x}, {real_y})",
                fill='white',
                font=('Arial', 10, 'bold'),
                tags='coords'
            )
    
    def on_mouse_click(self, event):
        """鼠标点击固定颜色"""
        if not self.image:
            return
        
        x = int(event.x / self.zoom_factor)
        y = int(event.y / self.zoom_factor)
        
        if 0 <= x < self.image.width and 0 <= y < self.image.height:
            pixel = self.image.getpixel((x, y))
            if len(pixel) == 4:
                pixel = pixel[:3]
            self.update_color_info(pixel)
            self.add_to_history(self.current_color)
            messagebox.showinfo("颜色已固定", 
                f"颜色：{self.get_color_name(self.current_rgb)}\n"
                f"HEX: {self.current_color}\n"
                f"RGB: {self.current_rgb}"
            )
    
    def update_color_info(self, rgb):
        """更新颜色信息"""
        if len(rgb) >= 3:
            r, g, b = rgb[0], rgb[1], rgb[2]
            self.current_rgb = (r, g, b)
            self.current_color = f'#{r:02x}{g:02x}{b:02x}'.upper()
            
            # 计算HSV
            h, s, v = colorsys.rgb_to_hsv(r/255, g/255, b/255)
            self.current_hsv = (h * 360, s * 100, v * 100)
            
            # 更新显示
            self.update_color_display()
    
    def update_color_display(self):
        """更新颜色显示"""
        # 更新颜色显示
        self.color_display.config(bg=self.current_color)
        
        # 选择文字颜色（深色背景用白色，浅色背景用黑色）
        r, g, b = self.current_rgb
        brightness = (r * 299 + g * 587 + b * 114) / 1000
        text_color = 'white' if brightness < 128 else 'black'
        self.color_display.config(fg=text_color)
        
        # 更新标签
        self.hex_label.config(text=self.current_color)
        self.rgb_label.config(text=f"({self.current_rgb[0]}, {self.current_rgb[1]}, {self.current_rgb[2]})")
        
        h, s, v = self.current_hsv
        self.hsv_label.config(text=f"({int(h)}°, {int(s)}%, {int(v)}%)")
        
        # 获取颜色名称
        color_name = self.get_color_name(self.current_rgb)
        self.name_label.config(text=color_name)
        
        # 获取相似颜色
        similar = self.get_similar_colors(self.current_rgb)
        self.sim_label.config(text=", ".join(similar[:3]) if similar else "无")
    
    def get_color_name(self, rgb):
        """获取颜色名称"""
        try:
            # 尝试获取精确颜色名称
            hex_color = f"#{rgb[0]:02x}{rgb[1]:02x}{rgb[2]:02x}"
            name = webcolors.hex_to_name(hex_color)
            return name
        except ValueError:
            # 获取最接近的颜色名称
            try:
                closest = webcolors.hex_to_name(hex_color, spec='css3')
                return closest
            except:
                # 使用自定义颜色名称
                r, g, b = rgb
                if r == g == b:
                    if r < 50:
                        return "黑色"
                    elif r < 150:
                        return "灰色"
                    else:
                        return "白色"
                
                # 判断颜色
                if r > 200 and g < 100 and b < 100:
                    return "红色"
                elif r > 200 and g > 150 and b < 100:
                    return "橙色"
                elif r > 200 and g > 200 and b < 100:
                    return "黄色"
                elif r < 100 and g > 200 and b < 100:
                    return "绿色"
                elif r < 100 and g > 200 and b > 200:
                    return "青色"
                elif r < 100 and g < 100 and b > 200:
                    return "蓝色"
                elif r > 200 and g < 100 and b > 200:
                    return "紫色"
                elif r > 200 and g < 150 and b > 150:
                    return "粉色"
                elif r > 150 and g > 100 and b < 50:
                    return "棕色"
                else:
                    return "自定义颜色"
    
    def get_similar_colors(self, rgb):
        """获取相似颜色"""
        similar = []
        for name, hex_color in self.common_colors.items():
            if hex_color == self.current_color:
                continue
            
            # 转换颜色
            r = int(hex_color[1:3], 16)
            g = int(hex_color[3:5], 16)
            b = int(hex_color[5:7], 16)
            
            # 计算颜色距离
            distance = ((rgb[0]-r)**2 + (rgb[1]-g)**2 + (rgb[2]-b)**2) ** 0.5
            
            if distance < 100:
                similar.append(name)
        
        return similar[:5]
    
    def add_to_history(self, color):
        """添加到历史"""
        if color not in self.color_history:
            self.color_history.append(color)
            if len(self.color_history) > self.max_history:
                self.color_history.pop(0)
            self.update_history_display()
    
    def update_history_display(self):
        """更新历史显示"""
        self.history_canvas.delete('all')
        
        if not self.color_history:
            return
        
        # 显示历史颜色
        count = len(self.color_history)
        width = 500 // count
        
        for i, color in enumerate(self.color_history):
            x = i * width + 5
            y = 5
            self.history_canvas.create_rectangle(
                x, y, x + width - 5, y + 40,
                fill=color,
                outline='#333',
                width=1
            )
            # 添加序号
            self.history_canvas.create_text(
                x + width//2, y + 55,
                text=f"#{i+1}",
                font=('Arial', 8),
                fill='#666'
            )
    
    def open_color_picker(self):
        """打开颜色选择器"""
        color = colorchooser.askcolor(
            title="选择颜色",
            initialcolor=self.current_color
        )
        if color:
            rgb = color[0]
            self.update_color_info((int(rgb[0]), int(rgb[1]), int(rgb[2])))
            self.add_to_history(self.current_color)
    
    def open_camera(self):
        """打开相机取色"""
        try:
            import cv2
            import numpy as np
            
            # 创建相机窗口
            cap = cv2.VideoCapture(0)
            
            if not cap.isOpened():
                messagebox.showerror("错误", "无法打开摄像头！")
                return
            
            # 创建窗口
            cv2.namedWindow('相机取色', cv2.WINDOW_NORMAL)
            cv2.resizeWindow('相机取色', 640, 480)
            
            # 提示信息
            cv2.putText(
                frame, "按 'c' 取色，按 'q' 退出",
                (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
                0.7, (0, 255, 0), 2
            )
            
            while True:
                ret, frame = cap.read()
                if not ret:
                    break
                
                # 显示取色区域
                h, w = frame.shape[:2]
                center_x, center_y = w//2, h//2
                
                # 绘制十字准星
                cv2.line(frame, (center_x-50, center_y), (center_x+50, center_y), (0, 255, 0), 2)
                cv2.line(frame, (center_x, center_y-50), (center_x, center_y+50), (0, 255, 0), 2)
                cv2.rectangle(frame, (center_x-5, center_y-5), (center_x+5, center_y+5), (0, 255, 0), 2)
                
                cv2.imshow('相机取色', frame)
                
                key = cv2.waitKey(1) & 0xFF
                if key == ord('q'):
                    break
                elif key == ord('c'):
                    # 取色
                    pixel = frame[center_y, center_x]
                    color = (int(pixel[2]), int(pixel[1]), int(pixel[0]))  # BGR to RGB
                    self.update_color_info(color)
                    self.add_to_history(self.current_color)
                    messagebox.showinfo("取色成功", 
                        f"颜色：{self.get_color_name(color)}\n"
                        f"HEX: {self.current_color}"
                    )
            
            cap.release()
            cv2.destroyAllWindows()
            
        except ImportError:
            messagebox.showerror("错误", 
                "请安装OpenCV：\npip install opencv-python\n"
                "或使用其他取色方式")
        except Exception as e:
            messagebox.showerror("错误", f"相机取色失败：{str(e)}")
    
    def copy_color(self):
        """复制颜色代码"""
        self.root.clipboard_clear()
        self.root.clipboard_append(self.current_color)
        messagebox.showinfo("成功", f"已复制颜色代码：{self.current_color}")

def main():
    root = tk.Tk()
    app = ColorIdentifier(root)
    root.mainloop()

if __name__ == "__main__":
    main()