-
Notifications
You must be signed in to change notification settings - Fork 2
/
grid.py
153 lines (125 loc) · 4.63 KB
/
grid.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
"""Takes as input the `notes` directory of the zipfile export from the
Post-it Plus app, and creates one picture per group with the images in
a nice grid.
"""
import collections
import json
import math
import os
import random
import sys
from slugify import slugify
import imagehash
from PIL import Image
X = 7
MAX_Y = 9
SIZE = 150
PAD = 5
def make_filename(key, extension):
"""Make a friendly filename for the image using the group key."""
key = unicode(key.strip())
return '{}.{}'.format(slugify(key), extension)
def read_duplicates(filename):
to_remove = set()
with open(filename) as infile:
duplicate_groups = json.load(infile)
total = 0
for group in duplicate_groups:
total += len(group)
for path in group[1:]:
to_remove.add(path)
return to_remove
def group_by_board_3csb(directory, dupes=set()):
master_json_filename = None
for filename in os.listdir(directory):
if filename.startswith('sheet') and filename.endswith('.json'):
master_json_filename = os.path.join(directory, filename)
break
if master_json_filename is None:
return None
with open(master_json_filename) as infile:
master = json.load(infile)
duplicates_removed = 0
grouped_by_board = collections.defaultdict(list)
grouped_counter = collections.Counter()
for cluster in master['clusters']:
cluster_name = cluster['name']
for note in cluster['notes']:
filename = 'note-{}-enhanced.jpg'.format(note['contentUUID'])
path = os.path.join(directory, filename)
if path not in dupes:
key = cluster_name
if grouped_counter[key]:
key_with_counter = '%s-%i' % (key, grouped_counter[key])
else:
key_with_counter = '%s' % key
grouped_by_board[key_with_counter].append(path)
if len(grouped_by_board[key_with_counter]) >= X * MAX_Y:
grouped_counter[key] += 1
else:
duplicates_removed += 1
print >> sys.stderr, 'Removed %i duplicates' % duplicates_removed
return sorted(grouped_by_board.items())
def group_by_board_zip(directory, dupes=set()):
duplicates_removed = 0
grouped_by_board = collections.defaultdict(list)
grouped_counter = collections.Counter()
for filename in os.listdir(directory):
path = os.path.join(directory, filename)
if path not in dupes:
key = filename.split('[')[1].split(']')[0]
if grouped_counter[key]:
key_with_counter = '%s-%i' % (key, grouped_counter[key])
else:
key_with_counter = '%s' % key
grouped_by_board[key_with_counter].append(path)
if len(grouped_by_board[key_with_counter]) >= X * MAX_Y:
grouped_counter[key] += 1
else:
duplicates_removed += 1
print >> sys.stderr, 'Removed %i duplicates' % duplicates_removed
return sorted(grouped_by_board.items())
def group_by_board(directory, dupes=set()):
first_try = group_by_board_3csb(directory, dupes=dupes)
if first_try:
return first_try
else:
return group_by_board_zip(directory, dupes=dupes)
# `notes` directory inside of zipfile export from post-it plus
notes_directory = sys.argv[1]
# if you've used the GUI to find duplicates, this is the filename of
# the JSON output
try:
duplicates_filename = sys.argv[2]
except IndexError:
dupes = set()
else:
dupes = read_duplicates(duplicates_filename)
for key, filename_list in group_by_board(notes_directory, dupes):
# TODO: how should we order these?
random.shuffle(filename_list)
# make new filename from key
new_filename = make_filename(key, 'png')
print >> sys.stderr, 'generating %s...' % new_filename
# calculate image sizes
n_images = len(filename_list)
rows = ((n_images - 1) / X) + 1
new_width = X * SIZE + (X - 1) * PAD
new_height = rows * SIZE + (rows - 1) * PAD
# make a new image big enough to hold the grid
new_image = Image.new(
'RGB',
(new_width, new_height),
color=(255, 255, 255),
)
for image_index, filename in enumerate(filename_list):
# open image
image = Image.open(filename)
# resize to square of SIZE x SIZE
resized = image.resize((SIZE, SIZE), Image.BICUBIC)
# place in the right grid position on new image
x_index = image_index % X
y_index = image_index / X
size = SIZE + PAD
new_image.paste(resized, (x_index * size, y_index * size))
new_image.save(new_filename, 'PNG')