-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcolordropper.py
121 lines (102 loc) · 4.26 KB
/
colordropper.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""
Color Eyedropper
Author: Israel Dryer
Modified: 2020-06-29
Instructions:
> Hover over the color you want to inspect.
> Scroll the mouse wheel to zoom in or out.
> Left-click to save color to clipboard and exit the program.
> Right-click to toggle between HEX and RGB color formats.
NOTES: There is a bug in Tkinter that prevents the Tk clipboard from transferring to the system
clipboard when the window is destroyed, at least on Windows. There are a few work-arounds for
this, but none of them worked for me. Thus, I am forced to use pyperclip to implement this
functionality when the window is destroyed. ---> https://bugs.python.org/issue23760
"""
import tkinter as tk
from tkinter import ttk
from PIL import ImageGrab, ImageTk, Image
import pyperclip
class ColorDropper(tk.Tk):
def __init__(self):
super().__init__()
self.wm_attributes('-fullscreen', 'true')
self.canvas = tk.Canvas(self, cursor='plus')
self.img_data = ImageGrab.grab()
self.img = ImageTk.PhotoImage(self.img_data)
self.mode = 'rgb'
self.zoom = 2
self.canvas.create_image(0, 0, image=self.img, anchor='nw')
self.canvas.pack(fill='both', expand='yes')
# event binding
self.bind("<Motion>", self.on_motion)
self.bind("<Button-1>", self.on_left_click)
self.bind("<Button-3>", self.on_right_click)
self.bind("<MouseWheel>", self.on_mouse_scroll)
# initial setup
self.snip = None
self.box_data = None
self.box_img = None
self.after(50, self.show_toplevel)
def on_mouse_scroll(self, event):
delta = event.delta / -120
if delta > 0 and self.zoom < 10:
self.zoom += delta
elif delta < 0 and self.zoom > 0:
self.zoom += delta
self.on_motion()
def on_left_click(self, event):
color = self.snip.color_var.get()
pyperclip.copy(color)
self.destroy()
def on_right_click(self, event):
"""Callback for right-click event. Toggle between hex and rgb color mode"""
self.mode = 'hex' if self.mode == 'rgb' else 'rgb'
self.on_motion()
def on_motion(self, event=None):
"""Callback for mouse motion"""
# get current mouse position
x, y = self.winfo_pointerxy()
# move snip window
self.snip.geometry(f'+{x+50}+{y-25}')
# update the snip image
bbox = (x-self.zoom, y-self.zoom, x+self.zoom+1, y+self.zoom+1)
self.box_data = self.img_data.crop(bbox).resize((50, 50), Image.BOX)
self.box_img = ImageTk.PhotoImage(self.box_data)
self.snip.canvas.create_image(0, 0, image=self.box_img, anchor='nw')
# update color text
text_color = self.get_colors()
self.snip.canvas.create_text(25, 25, text='+', fill=text_color)
def get_colors(self):
"""Extract the color from the target pixel"""
if self.mode == 'rgb':
r, g, b = self.box_data.getpixel((25, 25))
rgb_color = f'({r},{g},{b})'
self.snip.color_var.set(rgb_color)
offset = 255 - max(r, g, b)
else:
r, g, b = self.box_data.getpixel((25, 25))
hex_color = f'#{255-r:0>2x}{255-g:0>2x}{255-b:0>2x}'
self.snip.color_var.set(hex_color)
offset = 255 - max(r, g, b)
return f'#{offset:0>2x}{offset:0>2x}{offset:0>2x}'
def show_toplevel(self):
"""Display the toplevel Snip widget"""
self.snip = Snip(self)
self.on_motion()
class Snip(tk.Toplevel):
def __init__(self, master):
super().__init__(master, cursor='plus')
self.transient(master)
self.overrideredirect(True)
self.geometry('180x50')
self.lift()
self.canvas = tk.Canvas(self, height=50, width=50)
self.canvas.create_text(10, 10, text='+', fill='white')
self.color_var = tk.StringVar()
self.color_lbl = tk.Label(self, textvariable=self.color_var, font='-size 14')
# add widget to window
self.canvas.pack(side='left', fill='both')
self.color_lbl.pack(side='left', fill='both', expand='yes')
if __name__ == "__main__":
e = ColorDropper()
e.mainloop()