photo done
[rainbowstream.git] / rainbowstream / pure_image.py
1 from PIL import Image
2 from functools import partial
3
4 import sys
5 import os
6
7 CLUT = [ # color look-up table
8 # 8-bit, RGB hex
9
10 # Primary 3-bit (8 colors). Unique representation!
11 ('00', '000000'),
12 ('01', '800000'),
13 ('02', '008000'),
14 ('03', '808000'),
15 ('04', '000080'),
16 ('05', '800080'),
17 ('06', '008080'),
18 ('07', 'c0c0c0'),
19
20 # Equivalent "bright" versions of original 8 colors.
21 ('08', '808080'),
22 ('09', 'ff0000'),
23 ('10', '00ff00'),
24 ('11', 'ffff00'),
25 ('12', '0000ff'),
26 ('13', 'ff00ff'),
27 ('14', '00ffff'),
28 ('15', 'ffffff'),
29
30 # Strictly ascending.
31 ('16', '000000'),
32 ('17', '00005f'),
33 ('18', '000087'),
34 ('19', '0000af'),
35 ('20', '0000d7'),
36 ('21', '0000ff'),
37 ('22', '005f00'),
38 ('23', '005f5f'),
39 ('24', '005f87'),
40 ('25', '005faf'),
41 ('26', '005fd7'),
42 ('27', '005fff'),
43 ('28', '008700'),
44 ('29', '00875f'),
45 ('30', '008787'),
46 ('31', '0087af'),
47 ('32', '0087d7'),
48 ('33', '0087ff'),
49 ('34', '00af00'),
50 ('35', '00af5f'),
51 ('36', '00af87'),
52 ('37', '00afaf'),
53 ('38', '00afd7'),
54 ('39', '00afff'),
55 ('40', '00d700'),
56 ('41', '00d75f'),
57 ('42', '00d787'),
58 ('43', '00d7af'),
59 ('44', '00d7d7'),
60 ('45', '00d7ff'),
61 ('46', '00ff00'),
62 ('47', '00ff5f'),
63 ('48', '00ff87'),
64 ('49', '00ffaf'),
65 ('50', '00ffd7'),
66 ('51', '00ffff'),
67 ('52', '5f0000'),
68 ('53', '5f005f'),
69 ('54', '5f0087'),
70 ('55', '5f00af'),
71 ('56', '5f00d7'),
72 ('57', '5f00ff'),
73 ('58', '5f5f00'),
74 ('59', '5f5f5f'),
75 ('60', '5f5f87'),
76 ('61', '5f5faf'),
77 ('62', '5f5fd7'),
78 ('63', '5f5fff'),
79 ('64', '5f8700'),
80 ('65', '5f875f'),
81 ('66', '5f8787'),
82 ('67', '5f87af'),
83 ('68', '5f87d7'),
84 ('69', '5f87ff'),
85 ('70', '5faf00'),
86 ('71', '5faf5f'),
87 ('72', '5faf87'),
88 ('73', '5fafaf'),
89 ('74', '5fafd7'),
90 ('75', '5fafff'),
91 ('76', '5fd700'),
92 ('77', '5fd75f'),
93 ('78', '5fd787'),
94 ('79', '5fd7af'),
95 ('80', '5fd7d7'),
96 ('81', '5fd7ff'),
97 ('82', '5fff00'),
98 ('83', '5fff5f'),
99 ('84', '5fff87'),
100 ('85', '5fffaf'),
101 ('86', '5fffd7'),
102 ('87', '5fffff'),
103 ('88', '870000'),
104 ('89', '87005f'),
105 ('90', '870087'),
106 ('91', '8700af'),
107 ('92', '8700d7'),
108 ('93', '8700ff'),
109 ('94', '875f00'),
110 ('95', '875f5f'),
111 ('96', '875f87'),
112 ('97', '875faf'),
113 ('98', '875fd7'),
114 ('99', '875fff'),
115 ('100', '878700'),
116 ('101', '87875f'),
117 ('102', '878787'),
118 ('103', '8787af'),
119 ('104', '8787d7'),
120 ('105', '8787ff'),
121 ('106', '87af00'),
122 ('107', '87af5f'),
123 ('108', '87af87'),
124 ('109', '87afaf'),
125 ('110', '87afd7'),
126 ('111', '87afff'),
127 ('112', '87d700'),
128 ('113', '87d75f'),
129 ('114', '87d787'),
130 ('115', '87d7af'),
131 ('116', '87d7d7'),
132 ('117', '87d7ff'),
133 ('118', '87ff00'),
134 ('119', '87ff5f'),
135 ('120', '87ff87'),
136 ('121', '87ffaf'),
137 ('122', '87ffd7'),
138 ('123', '87ffff'),
139 ('124', 'af0000'),
140 ('125', 'af005f'),
141 ('126', 'af0087'),
142 ('127', 'af00af'),
143 ('128', 'af00d7'),
144 ('129', 'af00ff'),
145 ('130', 'af5f00'),
146 ('131', 'af5f5f'),
147 ('132', 'af5f87'),
148 ('133', 'af5faf'),
149 ('134', 'af5fd7'),
150 ('135', 'af5fff'),
151 ('136', 'af8700'),
152 ('137', 'af875f'),
153 ('138', 'af8787'),
154 ('139', 'af87af'),
155 ('140', 'af87d7'),
156 ('141', 'af87ff'),
157 ('142', 'afaf00'),
158 ('143', 'afaf5f'),
159 ('144', 'afaf87'),
160 ('145', 'afafaf'),
161 ('146', 'afafd7'),
162 ('147', 'afafff'),
163 ('148', 'afd700'),
164 ('149', 'afd75f'),
165 ('150', 'afd787'),
166 ('151', 'afd7af'),
167 ('152', 'afd7d7'),
168 ('153', 'afd7ff'),
169 ('154', 'afff00'),
170 ('155', 'afff5f'),
171 ('156', 'afff87'),
172 ('157', 'afffaf'),
173 ('158', 'afffd7'),
174 ('159', 'afffff'),
175 ('160', 'd70000'),
176 ('161', 'd7005f'),
177 ('162', 'd70087'),
178 ('163', 'd700af'),
179 ('164', 'd700d7'),
180 ('165', 'd700ff'),
181 ('166', 'd75f00'),
182 ('167', 'd75f5f'),
183 ('168', 'd75f87'),
184 ('169', 'd75faf'),
185 ('170', 'd75fd7'),
186 ('171', 'd75fff'),
187 ('172', 'd78700'),
188 ('173', 'd7875f'),
189 ('174', 'd78787'),
190 ('175', 'd787af'),
191 ('176', 'd787d7'),
192 ('177', 'd787ff'),
193 ('178', 'd7af00'),
194 ('179', 'd7af5f'),
195 ('180', 'd7af87'),
196 ('181', 'd7afaf'),
197 ('182', 'd7afd7'),
198 ('183', 'd7afff'),
199 ('184', 'd7d700'),
200 ('185', 'd7d75f'),
201 ('186', 'd7d787'),
202 ('187', 'd7d7af'),
203 ('188', 'd7d7d7'),
204 ('189', 'd7d7ff'),
205 ('190', 'd7ff00'),
206 ('191', 'd7ff5f'),
207 ('192', 'd7ff87'),
208 ('193', 'd7ffaf'),
209 ('194', 'd7ffd7'),
210 ('195', 'd7ffff'),
211 ('196', 'ff0000'),
212 ('197', 'ff005f'),
213 ('198', 'ff0087'),
214 ('199', 'ff00af'),
215 ('200', 'ff00d7'),
216 ('201', 'ff00ff'),
217 ('202', 'ff5f00'),
218 ('203', 'ff5f5f'),
219 ('204', 'ff5f87'),
220 ('205', 'ff5faf'),
221 ('206', 'ff5fd7'),
222 ('207', 'ff5fff'),
223 ('208', 'ff8700'),
224 ('209', 'ff875f'),
225 ('210', 'ff8787'),
226 ('211', 'ff87af'),
227 ('212', 'ff87d7'),
228 ('213', 'ff87ff'),
229 ('214', 'ffaf00'),
230 ('215', 'ffaf5f'),
231 ('216', 'ffaf87'),
232 ('217', 'ffafaf'),
233 ('218', 'ffafd7'),
234 ('219', 'ffafff'),
235 ('220', 'ffd700'),
236 ('221', 'ffd75f'),
237 ('222', 'ffd787'),
238 ('223', 'ffd7af'),
239 ('224', 'ffd7d7'),
240 ('225', 'ffd7ff'),
241 ('226', 'ffff00'),
242 ('227', 'ffff5f'),
243 ('228', 'ffff87'),
244 ('229', 'ffffaf'),
245 ('230', 'ffffd7'),
246 ('231', 'ffffff'),
247
248 # Gray-scale range.
249 ('232', '080808'),
250 ('233', '121212'),
251 ('234', '1c1c1c'),
252 ('235', '262626'),
253 ('236', '303030'),
254 ('237', '3a3a3a'),
255 ('238', '444444'),
256 ('239', '4e4e4e'),
257 ('240', '585858'),
258 ('241', '626262'),
259 ('242', '6c6c6c'),
260 ('243', '767676'),
261 ('244', '808080'),
262 ('245', '8a8a8a'),
263 ('246', '949494'),
264 ('247', '9e9e9e'),
265 ('248', 'a8a8a8'),
266 ('249', 'b2b2b2'),
267 ('250', 'bcbcbc'),
268 ('251', 'c6c6c6'),
269 ('252', 'd0d0d0'),
270 ('253', 'dadada'),
271 ('254', 'e4e4e4'),
272 ('255', 'eeeeee'),
273 ]
274
275
276 def _create_dicts():
277 short2rgb_dict = dict(CLUT)
278 rgb2short_dict = {}
279 for k, v in short2rgb_dict.items():
280 rgb2short_dict[v] = k
281 return rgb2short_dict, short2rgb_dict
282
283 RGB2SHORT_DICT, SHORT2RGB_DICT = _create_dicts()
284
285
286 def short2rgb(short):
287 return SHORT2RGB_DICT[short]
288
289
290 def pixel_print(ansicolor):
291 sys.stdout.write('\033[48;5;%sm \033[0m' % (ansicolor))
292
293
294 def hex_to_rgb(value):
295 value = value.lstrip('#')
296 lv = len(value)
297 return tuple(int(value[i:i + lv / 3], 16) for i in range(0, lv, lv / 3))
298
299
300 def rgb_to_hex(rgb):
301 return '%02x%02x%02x' % rgb
302
303
304 def rgb2short(r, g, b):
305 dist = lambda s, d: (s[0] - d[0]) ** 2 + \
306 (s[1] - d[1]) ** 2 + (s[2] - d[2]) ** 2
307 ary = [hex_to_rgb(hex) for hex in RGB2SHORT_DICT]
308 m = min(ary, key=partial(dist, (r, g, b)))
309 return RGB2SHORT_DICT[rgb_to_hex(m)]
310
311
312 def image_to_display(path):
313 i = Image.open(path)
314 i = i.convert('RGBA')
315 w, h = i.size
316 i.load()
317 rows, columns = os.popen('stty size', 'r').read().split()
318 width = min(w, int(columns) - 2 * 6)
319 height = int(float(h) * (float(width) / float(w)))
320 height //= 2
321 i = i.resize((width, height), Image.BICUBIC)
322 height = min(height, 30)
323
324 for y in xrange(height):
325 print ' ' * 6,
326 for x in xrange(width):
327 p = i.getpixel((x, y))
328 r, g, b = p[:3]
329 pixel_print(rgb2short(r, g, b))
330 print ''
331
332 if __name__ == '__main__':
333 image_to_display(sys.argv[1])