refactoring and add various comments
[rainbowstream.git] / rainbowstream / pure_image.py
... / ...
CommitLineData
1from PIL import Image
2from functools import partial
3from .config import *
4
5import sys
6import os
7
8"""
9This file is borrowed from following gist:
10https://gist.github.com/MicahElliott/719710
11It's too slow in compare with C program.
12"""
13
14CLUT = [ # 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
283def _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
293RGB2SHORT_DICT, SHORT2RGB_DICT = _create_dicts()
294
295
296def short2rgb(short):
297 """
298 Short to RGB
299 """
300 return SHORT2RGB_DICT[short]
301
302
303def 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
310def 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
319def rgb_to_hex(rgb):
320 """
321 RGB to Hex
322 """
323 return '%02x%02x%02x' % rgb
324
325
326def 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
337def 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"""
366For direct using purpose
367"""
368if __name__ == '__main__':
369 image_to_display(sys.argv[1])