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