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