fixed issue 19, stream is thread now
[rainbowstream.git] / rainbowstream / pure_image.py
CommitLineData
0418d443 1from PIL import Image
026caf17 2from functools import partial
816e305f 3from .config import *
1c50e2d1 4
991c30af
O
5import sys
6import os
1c50e2d1 7
f5677fb1
O
8"""
9This file is borrowed from following gist:
10https://gist.github.com/MicahElliott/719710
d72a5869 11It's too slow in compare with C program.
f5677fb1
O
12"""
13
1c50e2d1 14CLUT = [ # color look-up table
991c30af 15 # 8-bit, RGB hex
1c50e2d1
O
16
17 # Primary 3-bit (8 colors). Unique representation!
991c30af
O
18 ('00', '000000'),
19 ('01', '800000'),
20 ('02', '008000'),
21 ('03', '808000'),
22 ('04', '000080'),
23 ('05', '800080'),
24 ('06', '008080'),
25 ('07', 'c0c0c0'),
1c50e2d1
O
26
27 # Equivalent "bright" versions of original 8 colors.
991c30af
O
28 ('08', '808080'),
29 ('09', 'ff0000'),
30 ('10', '00ff00'),
31 ('11', 'ffff00'),
32 ('12', '0000ff'),
33 ('13', 'ff00ff'),
34 ('14', '00ffff'),
35 ('15', 'ffffff'),
1c50e2d1
O
36
37 # Strictly ascending.
991c30af
O
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'),
1c50e2d1
O
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
991c30af 282
1c50e2d1 283def _create_dicts():
531f5682
O
284 """
285 Create dictionary
286 """
1c50e2d1
O
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
60431c3b 293RGB2SHORT_DICT, SHORT2RGB_DICT = _create_dicts()
294
295
1c50e2d1 296def short2rgb(short):
531f5682
O
297 """
298 Short to RGB
299 """
1c50e2d1
O
300 return SHORT2RGB_DICT[short]
301
60431c3b 302
2b502606 303def pixel_print(ansicolor):
531f5682
O
304 """
305 Print a pixel with given Ansi color
306 """
2b502606 307 sys.stdout.write('\033[48;5;%sm \033[0m' % (ansicolor))
308
60431c3b 309
25e5e7f4 310def hex_to_rgb(value):
531f5682
O
311 """
312 Hex to RGB
313 """
25e5e7f4 314 value = value.lstrip('#')
315 lv = len(value)
991c30af 316 return tuple(int(value[i:i + lv / 3], 16) for i in range(0, lv, lv / 3))
25e5e7f4 317
60431c3b 318
25e5e7f4 319def rgb_to_hex(rgb):
531f5682
O
320 """
321 RGB to Hex
322 """
60431c3b 323 return '%02x%02x%02x' % rgb
25e5e7f4 324
026caf17 325
60431c3b 326def rgb2short(r, g, b):
531f5682
O
327 """
328 RGB to short
329 """
991c30af
O
330 dist = lambda s, d: (s[0] - d[0]) ** 2 + \
331 (s[1] - d[1]) ** 2 + (s[2] - d[2]) ** 2
2b502606 332 ary = [hex_to_rgb(hex) for hex in RGB2SHORT_DICT]
991c30af 333 m = min(ary, key=partial(dist, (r, g, b)))
60431c3b 334 return RGB2SHORT_DICT[rgb_to_hex(m)]
1c50e2d1 335
991c30af 336
422dd385 337def image_to_display(path, start=None, length=None):
531f5682
O
338 """
339 Display an image
340 """
4592d231 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
991c30af 346 i = Image.open(path)
2b502606 347 i = i.convert('RGBA')
991c30af 348 w, h = i.size
2b502606 349 i.load()
4592d231 350 width = min(w, length)
2b502606 351 height = int(float(h) * (float(width) / float(w)))
352 height //= 2
353 i = i.resize((width, height), Image.BICUBIC)
816e305f 354 height = min(height, IMAGE_MAX_HEIGHT)
2b502606 355
356 for y in xrange(height):
2e1241c7 357 sys.stdout.write(' ' * start)
2b502606 358 for x in xrange(width):
991c30af 359 p = i.getpixel((x, y))
2b502606 360 r, g, b = p[:3]
991c30af 361 pixel_print(rgb2short(r, g, b))
2e1241c7 362 sys.stdout.write('\n')
25e5e7f4 363
531f5682
O
364
365"""
366For direct using purpose
367"""
1c50e2d1 368if __name__ == '__main__':
60431c3b 369 image_to_display(sys.argv[1])