add func
[rainbowstream.git] / rainbowstream / image.py
CommitLineData
25e5e7f4 1from PIL import Image
1c50e2d1
O
2
3""" Convert values between RGB hex codes and xterm-256 color codes.
4
5Nice long listing of all 256 colors and their codes. Useful for
6developing console color themes, or even script output schemes.
7
8Resources:
9* http://en.wikipedia.org/wiki/8-bit_color
10* http://en.wikipedia.org/wiki/ANSI_escape_code
11* /usr/share/X11/rgb.txt
12
13I'm not sure where this script was inspired from. I think I must have
14written it from scratch, though it's been several years now.
15"""
16
17__author__ = 'Micah Elliott http://MicahElliott.com'
18__version__ = '0.1'
19__copyright__ = 'Copyright (C) 2011 Micah Elliott. All rights reserved.'
20__license__ = 'WTFPL http://sam.zoy.org/wtfpl/'
21
22#---------------------------------------------------------------------
23
24import sys, re
25
26CLUT = [ # color look-up table
27# 8-bit, RGB hex
28
29 # Primary 3-bit (8 colors). Unique representation!
30 ('00', '000000'),
31 ('01', '800000'),
32 ('02', '008000'),
33 ('03', '808000'),
34 ('04', '000080'),
35 ('05', '800080'),
36 ('06', '008080'),
37 ('07', 'c0c0c0'),
38
39 # Equivalent "bright" versions of original 8 colors.
40 ('08', '808080'),
41 ('09', 'ff0000'),
42 ('10', '00ff00'),
43 ('11', 'ffff00'),
44 ('12', '0000ff'),
45 ('13', 'ff00ff'),
46 ('14', '00ffff'),
47 ('15', 'ffffff'),
48
49 # Strictly ascending.
50 ('16', '000000'),
51 ('17', '00005f'),
52 ('18', '000087'),
53 ('19', '0000af'),
54 ('20', '0000d7'),
55 ('21', '0000ff'),
56 ('22', '005f00'),
57 ('23', '005f5f'),
58 ('24', '005f87'),
59 ('25', '005faf'),
60 ('26', '005fd7'),
61 ('27', '005fff'),
62 ('28', '008700'),
63 ('29', '00875f'),
64 ('30', '008787'),
65 ('31', '0087af'),
66 ('32', '0087d7'),
67 ('33', '0087ff'),
68 ('34', '00af00'),
69 ('35', '00af5f'),
70 ('36', '00af87'),
71 ('37', '00afaf'),
72 ('38', '00afd7'),
73 ('39', '00afff'),
74 ('40', '00d700'),
75 ('41', '00d75f'),
76 ('42', '00d787'),
77 ('43', '00d7af'),
78 ('44', '00d7d7'),
79 ('45', '00d7ff'),
80 ('46', '00ff00'),
81 ('47', '00ff5f'),
82 ('48', '00ff87'),
83 ('49', '00ffaf'),
84 ('50', '00ffd7'),
85 ('51', '00ffff'),
86 ('52', '5f0000'),
87 ('53', '5f005f'),
88 ('54', '5f0087'),
89 ('55', '5f00af'),
90 ('56', '5f00d7'),
91 ('57', '5f00ff'),
92 ('58', '5f5f00'),
93 ('59', '5f5f5f'),
94 ('60', '5f5f87'),
95 ('61', '5f5faf'),
96 ('62', '5f5fd7'),
97 ('63', '5f5fff'),
98 ('64', '5f8700'),
99 ('65', '5f875f'),
100 ('66', '5f8787'),
101 ('67', '5f87af'),
102 ('68', '5f87d7'),
103 ('69', '5f87ff'),
104 ('70', '5faf00'),
105 ('71', '5faf5f'),
106 ('72', '5faf87'),
107 ('73', '5fafaf'),
108 ('74', '5fafd7'),
109 ('75', '5fafff'),
110 ('76', '5fd700'),
111 ('77', '5fd75f'),
112 ('78', '5fd787'),
113 ('79', '5fd7af'),
114 ('80', '5fd7d7'),
115 ('81', '5fd7ff'),
116 ('82', '5fff00'),
117 ('83', '5fff5f'),
118 ('84', '5fff87'),
119 ('85', '5fffaf'),
120 ('86', '5fffd7'),
121 ('87', '5fffff'),
122 ('88', '870000'),
123 ('89', '87005f'),
124 ('90', '870087'),
125 ('91', '8700af'),
126 ('92', '8700d7'),
127 ('93', '8700ff'),
128 ('94', '875f00'),
129 ('95', '875f5f'),
130 ('96', '875f87'),
131 ('97', '875faf'),
132 ('98', '875fd7'),
133 ('99', '875fff'),
134 ('100', '878700'),
135 ('101', '87875f'),
136 ('102', '878787'),
137 ('103', '8787af'),
138 ('104', '8787d7'),
139 ('105', '8787ff'),
140 ('106', '87af00'),
141 ('107', '87af5f'),
142 ('108', '87af87'),
143 ('109', '87afaf'),
144 ('110', '87afd7'),
145 ('111', '87afff'),
146 ('112', '87d700'),
147 ('113', '87d75f'),
148 ('114', '87d787'),
149 ('115', '87d7af'),
150 ('116', '87d7d7'),
151 ('117', '87d7ff'),
152 ('118', '87ff00'),
153 ('119', '87ff5f'),
154 ('120', '87ff87'),
155 ('121', '87ffaf'),
156 ('122', '87ffd7'),
157 ('123', '87ffff'),
158 ('124', 'af0000'),
159 ('125', 'af005f'),
160 ('126', 'af0087'),
161 ('127', 'af00af'),
162 ('128', 'af00d7'),
163 ('129', 'af00ff'),
164 ('130', 'af5f00'),
165 ('131', 'af5f5f'),
166 ('132', 'af5f87'),
167 ('133', 'af5faf'),
168 ('134', 'af5fd7'),
169 ('135', 'af5fff'),
170 ('136', 'af8700'),
171 ('137', 'af875f'),
172 ('138', 'af8787'),
173 ('139', 'af87af'),
174 ('140', 'af87d7'),
175 ('141', 'af87ff'),
176 ('142', 'afaf00'),
177 ('143', 'afaf5f'),
178 ('144', 'afaf87'),
179 ('145', 'afafaf'),
180 ('146', 'afafd7'),
181 ('147', 'afafff'),
182 ('148', 'afd700'),
183 ('149', 'afd75f'),
184 ('150', 'afd787'),
185 ('151', 'afd7af'),
186 ('152', 'afd7d7'),
187 ('153', 'afd7ff'),
188 ('154', 'afff00'),
189 ('155', 'afff5f'),
190 ('156', 'afff87'),
191 ('157', 'afffaf'),
192 ('158', 'afffd7'),
193 ('159', 'afffff'),
194 ('160', 'd70000'),
195 ('161', 'd7005f'),
196 ('162', 'd70087'),
197 ('163', 'd700af'),
198 ('164', 'd700d7'),
199 ('165', 'd700ff'),
200 ('166', 'd75f00'),
201 ('167', 'd75f5f'),
202 ('168', 'd75f87'),
203 ('169', 'd75faf'),
204 ('170', 'd75fd7'),
205 ('171', 'd75fff'),
206 ('172', 'd78700'),
207 ('173', 'd7875f'),
208 ('174', 'd78787'),
209 ('175', 'd787af'),
210 ('176', 'd787d7'),
211 ('177', 'd787ff'),
212 ('178', 'd7af00'),
213 ('179', 'd7af5f'),
214 ('180', 'd7af87'),
215 ('181', 'd7afaf'),
216 ('182', 'd7afd7'),
217 ('183', 'd7afff'),
218 ('184', 'd7d700'),
219 ('185', 'd7d75f'),
220 ('186', 'd7d787'),
221 ('187', 'd7d7af'),
222 ('188', 'd7d7d7'),
223 ('189', 'd7d7ff'),
224 ('190', 'd7ff00'),
225 ('191', 'd7ff5f'),
226 ('192', 'd7ff87'),
227 ('193', 'd7ffaf'),
228 ('194', 'd7ffd7'),
229 ('195', 'd7ffff'),
230 ('196', 'ff0000'),
231 ('197', 'ff005f'),
232 ('198', 'ff0087'),
233 ('199', 'ff00af'),
234 ('200', 'ff00d7'),
235 ('201', 'ff00ff'),
236 ('202', 'ff5f00'),
237 ('203', 'ff5f5f'),
238 ('204', 'ff5f87'),
239 ('205', 'ff5faf'),
240 ('206', 'ff5fd7'),
241 ('207', 'ff5fff'),
242 ('208', 'ff8700'),
243 ('209', 'ff875f'),
244 ('210', 'ff8787'),
245 ('211', 'ff87af'),
246 ('212', 'ff87d7'),
247 ('213', 'ff87ff'),
248 ('214', 'ffaf00'),
249 ('215', 'ffaf5f'),
250 ('216', 'ffaf87'),
251 ('217', 'ffafaf'),
252 ('218', 'ffafd7'),
253 ('219', 'ffafff'),
254 ('220', 'ffd700'),
255 ('221', 'ffd75f'),
256 ('222', 'ffd787'),
257 ('223', 'ffd7af'),
258 ('224', 'ffd7d7'),
259 ('225', 'ffd7ff'),
260 ('226', 'ffff00'),
261 ('227', 'ffff5f'),
262 ('228', 'ffff87'),
263 ('229', 'ffffaf'),
264 ('230', 'ffffd7'),
265 ('231', 'ffffff'),
266
267 # Gray-scale range.
268 ('232', '080808'),
269 ('233', '121212'),
270 ('234', '1c1c1c'),
271 ('235', '262626'),
272 ('236', '303030'),
273 ('237', '3a3a3a'),
274 ('238', '444444'),
275 ('239', '4e4e4e'),
276 ('240', '585858'),
277 ('241', '626262'),
278 ('242', '6c6c6c'),
279 ('243', '767676'),
280 ('244', '808080'),
281 ('245', '8a8a8a'),
282 ('246', '949494'),
283 ('247', '9e9e9e'),
284 ('248', 'a8a8a8'),
285 ('249', 'b2b2b2'),
286 ('250', 'bcbcbc'),
287 ('251', 'c6c6c6'),
288 ('252', 'd0d0d0'),
289 ('253', 'dadada'),
290 ('254', 'e4e4e4'),
291 ('255', 'eeeeee'),
292]
293
294def _str2hex(hexstr):
295 return int(hexstr, 16)
296
297def _strip_hash(rgb):
298 # Strip leading `#` if exists.
299 if rgb.startswith('#'):
300 rgb = rgb.lstrip('#')
301 return rgb
302
303def _create_dicts():
304 short2rgb_dict = dict(CLUT)
305 rgb2short_dict = {}
306 for k, v in short2rgb_dict.items():
307 rgb2short_dict[v] = k
308 return rgb2short_dict, short2rgb_dict
309
310def short2rgb(short):
311 return SHORT2RGB_DICT[short]
312
313def print_all():
314 """ Print all 256 xterm color codes.
315 """
316 for short, rgb in CLUT:
317 sys.stdout.write('\033[48;5;%sm%s:%s' % (short, short, rgb))
318 sys.stdout.write("\033[0m ")
319 sys.stdout.write('\033[38;5;%sm%s:%s' % (short, short, rgb))
320 sys.stdout.write("\033[0m\n")
321 print "Printed all codes."
322 print "You can translate a hex or 0-255 code by providing an argument."
323
25e5e7f4 324def hex_to_rgb(value):
325 value = value.lstrip('#')
326 lv = len(value)
327 return tuple(int(value[i:i+lv/3], 16) for i in range(0, lv, lv/3))
328
329def rgb_to_hex(rgb):
330 return '#%02x%02x%02x' % rgb
331
1c50e2d1
O
332def rgb2short(rgb):
333 """ Find the closest xterm-256 approximation to the given RGB value.
334 @param rgb: Hex code representing an RGB value, eg, 'abcdef'
335 @returns: String between 0 and 255, compatible with xterm.
336 >>> rgb2short('123456')
337 ('23', '005f5f')
338 >>> rgb2short('ffffff')
339 ('231', 'ffffff')
340 >>> rgb2short('0DADD6') # vimeo logo
341 ('38', '00afd7')
342 """
343 rgb = _strip_hash(rgb)
344 incs = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff)
345 # Break 6-char RGB code into 3 integer vals.
346 parts = [ int(h, 16) for h in re.split(r'(..)(..)(..)', rgb)[1:4] ]
347 res = []
348 for part in parts:
349 i = 0
350 while i < len(incs)-1:
351 s, b = incs[i], incs[i+1] # smaller, bigger
352 if s <= part <= b:
353 s1 = abs(s - part)
354 b1 = abs(b - part)
355 if s1 < b1: closest = s
356 else: closest = b
357 res.append(closest)
358 break
359 i += 1
360 #print '***', res
361 res = ''.join([ ('%02.x' % i) for i in res ])
362 equiv = RGB2SHORT_DICT[ res ]
363 #print '***', res, equiv
364 return equiv, res
365
366RGB2SHORT_DICT, SHORT2RGB_DICT = _create_dicts()
367
25e5e7f4 368def imgge_to_display(path):
369 i = Image.open(path)
370 return
371
1c50e2d1
O
372#---------------------------------------------------------------------
373
374if __name__ == '__main__':
375 import doctest
376 doctest.testmod()
377 if len(sys.argv) == 1:
378 print_all()
379 raise SystemExit
380 arg = sys.argv[1]
381 if len(arg) < 4 and int(arg) < 256:
382 rgb = short2rgb(arg)
383 sys.stdout.write('xterm color \033[38;5;%sm%s\033[0m -> RGB exact \033[38;5;%sm%s\033[0m' % (arg, arg, arg, rgb))
384 sys.stdout.write("\033[0m\n")
385 else:
386 short, rgb = rgb2short(arg)
387 sys.stdout.write('RGB %s -> xterm color approx \033[38;5;%sm%s (%s)' % (arg, short, short, rgb))
25e5e7f4 388 sys.stdout.write("\033[0m\n")