-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patheyecatchingutil.py
338 lines (269 loc) · 10.2 KB
/
eyecatchingutil.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
import subprocess
import os
import sys
import shutil
import imagehash
from PIL import Image
from urllib.parse import urlparse
class MetaImage:
def __init__(self, imagename):
self.imagename = imagename
self.prefix = imagename.split(".")[0].split("_")[0]
self.image = Image.open(self.imagename)
self.size = self.image.size
self.width = self.image.size[0]
self.height = self.image.size[1]
self.name = self.imagename.split(".")[0]
self.ext = self.imagename.split(".")[1]
l, t, r, b = self.image.getbbox()
self.coordinates = Coordinates(l, t, r, b)
def get_coordinates(self):
return self.coordinates.as_tuple()
def get_cropped(self, coordinates):
if isinstance(coordinates, Coordinates):
coords = coordinates.as_tuple()
else:
coords = coordinates
return self.image.crop(coords)
def left_half(self):
return self.image.crop(self.coordinates.left_half())
def right_half(self):
return self.image.crop(self.coordinates.right_half())
def top_half(self):
return self.image.crop(self.coordinates.top_half())
def bottom_half(self):
return self.image.crop(self.coordinates.bottom_half())
def is_landscape(self):
return self.width > self.height
def is_potrait(self):
return self.height > self.width
def first_half(self):
if self.is_landscape():
return self.left_half()
if self.is_potrait():
return self.top_half()
def second_half(self):
if self.is_landscape():
return self.right_half()
if self.is_potrait():
return self.bottom_half()
def save(self, name = None):
if name is None:
self.image.save(self.imagename)
else:
self.image.save(name)
class Coordinates:
def __init__(self, l, t, r, b):
self.x1 = l
self.y1 = t
self.x2 = r
self.y2 = b
self.width = abs(self.x1 - self.x2)
self.height = abs(self.y1 - self.y2)
mid_x = int(self.width / 2)
mid_y = int(self.height / 2)
self.mid_x = mid_x if (self.width % 2) == 0 else mid_x + 1
self.mid_y = mid_y if (self.height % 2) == 0 else mid_y + 1
def as_tuple(self):
return (
self.x1, self.y1,
self.x2, self.y2
)
def get_area(self):
return self.width * self. height
def add_to_right(self, pixels: int):
return (
self.x1, self.y1,
self.x2 + pixels, self.y2
)
def add_to_bottom(self, pixels: int):
return (
self.x1, self.y1,
self.x2, self.y2 + pixels
)
def left_half(self):
return (
self.x1, self.y1,
self.x1 + self.mid_x, self.y2
)
def right_half(self):
return (
self.x1 + self.mid_x, self.y1,
self.x2, self.y2
)
def top_half(self):
return (
self.x1, self.y1,
self.x2, self.y1 + self.mid_y
)
def bottom_half(self):
return (
self.x1, self.y1 + self.mid_y,
self.x2, self.y2
)
def is_potrait(self):
return abs(self.x2 - self.x1) <= abs(self.y2 - self.y1)
def is_landscape(self):
return abs(self.x2 - self.x1) >= abs(self.y2 - self.y1)
def first_half(self):
if self.is_landscape():
return self.left_half()
if self.is_potrait():
return self.top_half()
def second_half(self):
if self.is_landscape():
return self.right_half()
if self.is_potrait():
return self.bottom_half()
class ImageComparator:
def __init__(self, image1: Image.Image, image2: Image.Image):
self.image1 = image1
self.image2 = image2
def is_similar(self, algorithm = "ahash"):
switcher = {
'ahash': self.is_similar_a_hash,
'phash': self.is_similar_p_hash,
'dhash': self.is_similar_d_hash,
'whash': self.is_similar_w_hash,
}
return switcher[algorithm]()
def hamming_diff(self, algorithm = "ahash"):
switcher = {
'ahash': self.hamming_diff_a_hash,
'phash': self.hamming_diff_p_hash,
'dhash': self.hamming_diff_d_hash,
'whash': self.hamming_diff_w_hash
}
return switcher[algorithm]()
def hash_diff(self, algorithm = "ahash"):
return self.hamming_diff(algorithm)
def hash_diff_percent(self, algorithm = "ahash"):
return 100 * self.hamming_diff(algorithm) / 64
def is_similar_by_color(self):
# take a random pixel
color1 = self.image1.getpixel((1, 1))
color2 = self.image2.getpixel((1, 1))
return color1 == color2
def is_similar_a_hash(self):
return imagehash.average_hash(self.image1) == imagehash.average_hash(self.image2)
def is_similar_p_hash(self):
return imagehash.phash(self.image1) == imagehash.phash(self.image2)
def is_similar_d_hash(self):
return imagehash.dhash(self.image1) == imagehash.dhash(self.image2)
def is_similar_w_hash(self):
return imagehash.whash(self.image1) == imagehash.whash(self.image2)
def hamming_diff_a_hash(self):
return abs(imagehash.average_hash(self.image1) - imagehash.average_hash(self.image2))
def hamming_diff_p_hash(self):
return abs(imagehash.phash(self.image1) - imagehash.phash(self.image2))
def hamming_diff_d_hash(self):
return abs(imagehash.dhash(self.image1) - imagehash.dhash(self.image2))
def hamming_diff_w_hash(self):
return abs(imagehash.whash(self.image1) - imagehash.whash(self.image2))
class BrowserScreenshot:
width = 1280
height = 0
ext = '.png'
def __init__(self, name):
self.name = name
self.imagename = name + self.ext
def size(self):
return (self.width, self.height)
def remove_pixels_right(self, pixels:int):
"""
Subtract given pixels from right side of the image
and replace the original file.
Used to remove scrollbar pixels.
"""
img = Image.open(self.imagename)
w, h = img.size
c = Coordinates(0, 0, w, h)
newimg = img.crop(c.add_to_right(-pixels))
img.close()
os.remove(self.imagename)
newimg.save(self.imagename)
self.height = newimg.size[1]
print("Info: \tRemoved {0} pixels from the right side of image {1}".format(pixels, self.imagename))
def extend_image(self, factor: int):
"""
Extend the image to be equally divisible by factor
"""
img = Image.open(self.imagename)
wd, ht = img.size
img.close()
ex_wd = factor - (wd % factor)
ex_ht = factor - (ht % factor)
if ex_ht != factor:
ex_ht_str = "0x{0}".format(ex_ht)
subprocess.call(["convert",
self.imagename,
"-gravity",
"south",
"-splice",
ex_ht_str,
self.imagename])
print("Info: \tExtended {0} pixels at the bottom of image {1}".format(ex_ht, self.imagename))
if ex_wd != factor:
ex_wd_str = "{0}x0".format(ex_wd)
subprocess.call(["convert",
self.imagename,
"-gravity",
"east",
"-splice",
ex_wd_str,
self.imagename])
print("Info: \tExtended {0} pixels at the right of image {1}".format(ex_wd, self.imagename))
class FirefoxScreenshot(BrowserScreenshot):
def __init__(self):
super().__init__('firefox')
def take_shot(self, url, height = 0):
"""
Take screenshot using Firefox
"""
print("Info: \tGetting screenshot from Firefox browser")
# add 10 px for scrollbar
window_size = "--window-size={0}".format(self.width + 10)
subprocess.call(["firefox",
"-screenshot",
window_size,
url])
# rename the output file
os.rename("screenshot.png", self.imagename)
# remove the scrolbar
self.remove_pixels_right(10)
print("Info: \tSaved screenshot from Firefox with name {0}".format(self.imagename))
print("Info: \tInitial image size: {0} x {1}".format(self.width, self.height))
class ChromeScreenshot(BrowserScreenshot):
def __init__(self):
super().__init__('chrome')
def take_shot_commandline(self, url, height):
"""
Take screenshot using Chrome
"""
print("Info: \tGetting screenshot from Chrome browser")
# chrome expects full viewport size
self.height = height
window_size = "--window-size={0},{1}".format(self.width, self.height)
subprocess.call(["/opt/google/chrome/chrome",
"--headless",
"--hide-scrollbars",
window_size,
"--screenshot",
url])
os.rename("screenshot.png", self.imagename)
print("Info: \tSaved screenshot from Chrome with name {0}".format(self.imagename))
print("Info: \tInitial image size: {0} x {1}".format(self.width, self.height))
def take_shot(self, url):
"""
Take screenshot using Puppeteer
"""
print("Info: \tGetting screenshot from Chrome browser")
# set width to class
subprocess.call(["node",
"puppeteer.js",
url,
str(self.width)])
os.rename("screenshot.png", self.imagename)
self.height = Image.open(self.imagename).size[1]
print("Info: \tSaved screenshot from Chrome with name {0}".format(self.imagename))
print("Info: \tInitial image size: {0} x {1}".format(self.width, self.height))