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