-
Notifications
You must be signed in to change notification settings - Fork 0
/
canvas.py
135 lines (108 loc) · 4.37 KB
/
canvas.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import tkinter as tk
import numpy as np
from PIL import ImageTk
from styles import MARGIN
from image import Image
from PIL import Image as PImage
from vertexes import VertexFinder
import styles
def center(coords):
'''Get the center of an rectangle'''
return (coords[0] + coords[2]) // 2, (coords[1] + coords[3]) // 2
class ImageCanvas(tk.Canvas):
'''A canvas which display the thumbnail of the image'''
def __init__(self, controller=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.controller = controller
self.image = None
self.thumbnail = None
self.image_to_show = 'product'
def config_size(self, size):
'''Update the canvas size'''
self.width, self.height = size
self.config(width=self.width, height=self.height)
def show_image(self, image):
'''Show an PIL Image'''
self.image = image
size = self.image_size(image)
self.config_size(size)
self.make_thumbnail()
self.create_image(
(0, 0), anchor=tk.NW, image=self.thumbnail)
def make_thumbnail(self):
'''Make a thumbnail of an PIL image'''
result = self.image.copy()
result.thumbnail((self.width, self.height), PImage.NEAREST)
self.thumbnail = ImageTk.PhotoImage(image=result)
def image_size(self, image):
'''Get the size of the thumbnail'''
if image.width > image.height:
width = self.controller.width
image_width = (width - 2*MARGIN) // 2
image_height = int(image_width * (image.height / image.width))
return image_width, image_height
height = self.controller.height
image_height = (height * 3) // 4
image_width = int(image_height * (image.width / image.height))
return image_width, image_height
class DragableCanvas(ImageCanvas):
'''A ImageCanvas which can drag the vertexes point'''
def __init__(self, controller, *args, **kwargs):
super().__init__(*args, **kwargs)
self.controller = controller
self.r = 15
self.selected = None
self.image_to_show = 'origin'
self.tag_bind('vertex', '<Button-1>', self.on_click)
self.bind('<Motion>', self.on_motion)
self.bind('<ButtonRelease-1>', self.on_release)
self.callback = None
def set_callback(self, callback):
'''Set the callback being called when the coords updates'''
self.callback = callback
def show_image(self, image, coords):
'''Show the image and draw the vertexes'''
super().show_image(image)
self.draw_vertexes(coords)
def draw_vertexes(self, coords):
'''Draw the four vertexes on the canvas'''
self.delete('vertex')
r = self.r
if coords is None:
coords = self.image.default_vertexes()
coords = self.coords_transform(coords)
[
self.create_oval(
x-r, y-r, x+r, y+r, fill=styles.COLOR, outline=styles.COLOR, tags=('vertex'))
for x, y in coords
]
self.draw_lines()
def draw_lines(self):
'''Draw the line between the vertexes'''
coords = self.get_coords()
coords = self.coords_transform(coords).tolist()
coords.append(coords[0])
self.delete('lines')
self.create_line(*coords, tags=('lines',), fill=styles.COLOR)
def on_click(self, event):
'''Find the current selected vertex'''
self.selected = self.find_closest(event.x, event.y)
def on_motion(self, event):
'''Move the selected vertex to the mouse'''
if self.selected:
self.coords(
self.selected, (event.x-self.r, event.y-self.r, event.x + self.r, event.y + self.r))
self.draw_lines()
def on_release(self, event):
'''Call the callback to update the coords'''
self.selected = None
self.callback(self.get_coords())
def get_coords(self):
'''Get the canvas coords of vertexes and transform to the image coords'''
coords = np.float32([center(self.coords(vertex))
for vertex in self.find_withtag('vertex')]) * self.image.width / self.width
print(coords.__repr__())
return coords
def coords_transform(self, coords):
'''Transform image coords to the canvas coords'''
return coords * self.width / self.image.width