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