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