1"""Tools for color handling in xonsh. 2 3This includes Convert values between RGB hex codes and xterm-256 4color codes. Parts of this file were originally forked from Micah Elliott 5http://MicahElliott.com Copyright (C) 2011 Micah Elliott. All rights reserved. 6WTFPL http://sam.zoy.org/wtfpl/ 7""" 8import re 9import math 10 11from xonsh.lazyasd import lazyobject, LazyObject 12from xonsh.tools import deprecated 13 14 15RE_BACKGROUND = LazyObject( 16 lambda: re.compile("(BG#|BGHEX|BACKGROUND)"), globals(), "RE_BACKGROUND" 17) 18 19 20@lazyobject 21def BASE_XONSH_COLORS(): 22 return { 23 "BLACK": (0, 0, 0), 24 "RED": (170, 0, 0), 25 "GREEN": (0, 170, 0), 26 "YELLOW": (170, 85, 0), 27 "BLUE": (0, 0, 170), 28 "PURPLE": (170, 0, 170), 29 "CYAN": (0, 170, 170), 30 "WHITE": (170, 170, 170), 31 "INTENSE_BLACK": (85, 85, 85), 32 "INTENSE_RED": (255, 85, 85), 33 "INTENSE_GREEN": (85, 255, 85), 34 "INTENSE_YELLOW": (255, 255, 85), 35 "INTENSE_BLUE": (85, 85, 255), 36 "INTENSE_PURPLE": (255, 85, 255), 37 "INTENSE_CYAN": (85, 255, 255), 38 "INTENSE_WHITE": (255, 255, 255), 39 } 40 41 42@lazyobject 43def CLUT(): 44 """color look-up table""" 45 return [ 46 # 8-bit, RGB hex 47 # Primary 3-bit (8 colors). Unique representation! 48 ("00", "000000"), 49 ("01", "800000"), 50 ("02", "008000"), 51 ("03", "808000"), 52 ("04", "000080"), 53 ("05", "800080"), 54 ("06", "008080"), 55 ("07", "c0c0c0"), 56 # Equivalent "bright" versions of original 8 colors. 57 ("08", "808080"), 58 ("09", "ff0000"), 59 ("10", "00ff00"), 60 ("11", "ffff00"), 61 ("12", "0000ff"), 62 ("13", "ff00ff"), 63 ("14", "00ffff"), 64 ("15", "ffffff"), 65 # Strictly ascending. 66 ("16", "000000"), 67 ("17", "00005f"), 68 ("18", "000087"), 69 ("19", "0000af"), 70 ("20", "0000d7"), 71 ("21", "0000ff"), 72 ("22", "005f00"), 73 ("23", "005f5f"), 74 ("24", "005f87"), 75 ("25", "005faf"), 76 ("26", "005fd7"), 77 ("27", "005fff"), 78 ("28", "008700"), 79 ("29", "00875f"), 80 ("30", "008787"), 81 ("31", "0087af"), 82 ("32", "0087d7"), 83 ("33", "0087ff"), 84 ("34", "00af00"), 85 ("35", "00af5f"), 86 ("36", "00af87"), 87 ("37", "00afaf"), 88 ("38", "00afd7"), 89 ("39", "00afff"), 90 ("40", "00d700"), 91 ("41", "00d75f"), 92 ("42", "00d787"), 93 ("43", "00d7af"), 94 ("44", "00d7d7"), 95 ("45", "00d7ff"), 96 ("46", "00ff00"), 97 ("47", "00ff5f"), 98 ("48", "00ff87"), 99 ("49", "00ffaf"), 100 ("50", "00ffd7"), 101 ("51", "00ffff"), 102 ("52", "5f0000"), 103 ("53", "5f005f"), 104 ("54", "5f0087"), 105 ("55", "5f00af"), 106 ("56", "5f00d7"), 107 ("57", "5f00ff"), 108 ("58", "5f5f00"), 109 ("59", "5f5f5f"), 110 ("60", "5f5f87"), 111 ("61", "5f5faf"), 112 ("62", "5f5fd7"), 113 ("63", "5f5fff"), 114 ("64", "5f8700"), 115 ("65", "5f875f"), 116 ("66", "5f8787"), 117 ("67", "5f87af"), 118 ("68", "5f87d7"), 119 ("69", "5f87ff"), 120 ("70", "5faf00"), 121 ("71", "5faf5f"), 122 ("72", "5faf87"), 123 ("73", "5fafaf"), 124 ("74", "5fafd7"), 125 ("75", "5fafff"), 126 ("76", "5fd700"), 127 ("77", "5fd75f"), 128 ("78", "5fd787"), 129 ("79", "5fd7af"), 130 ("80", "5fd7d7"), 131 ("81", "5fd7ff"), 132 ("82", "5fff00"), 133 ("83", "5fff5f"), 134 ("84", "5fff87"), 135 ("85", "5fffaf"), 136 ("86", "5fffd7"), 137 ("87", "5fffff"), 138 ("88", "870000"), 139 ("89", "87005f"), 140 ("90", "870087"), 141 ("91", "8700af"), 142 ("92", "8700d7"), 143 ("93", "8700ff"), 144 ("94", "875f00"), 145 ("95", "875f5f"), 146 ("96", "875f87"), 147 ("97", "875faf"), 148 ("98", "875fd7"), 149 ("99", "875fff"), 150 ("100", "878700"), 151 ("101", "87875f"), 152 ("102", "878787"), 153 ("103", "8787af"), 154 ("104", "8787d7"), 155 ("105", "8787ff"), 156 ("106", "87af00"), 157 ("107", "87af5f"), 158 ("108", "87af87"), 159 ("109", "87afaf"), 160 ("110", "87afd7"), 161 ("111", "87afff"), 162 ("112", "87d700"), 163 ("113", "87d75f"), 164 ("114", "87d787"), 165 ("115", "87d7af"), 166 ("116", "87d7d7"), 167 ("117", "87d7ff"), 168 ("118", "87ff00"), 169 ("119", "87ff5f"), 170 ("120", "87ff87"), 171 ("121", "87ffaf"), 172 ("122", "87ffd7"), 173 ("123", "87ffff"), 174 ("124", "af0000"), 175 ("125", "af005f"), 176 ("126", "af0087"), 177 ("127", "af00af"), 178 ("128", "af00d7"), 179 ("129", "af00ff"), 180 ("130", "af5f00"), 181 ("131", "af5f5f"), 182 ("132", "af5f87"), 183 ("133", "af5faf"), 184 ("134", "af5fd7"), 185 ("135", "af5fff"), 186 ("136", "af8700"), 187 ("137", "af875f"), 188 ("138", "af8787"), 189 ("139", "af87af"), 190 ("140", "af87d7"), 191 ("141", "af87ff"), 192 ("142", "afaf00"), 193 ("143", "afaf5f"), 194 ("144", "afaf87"), 195 ("145", "afafaf"), 196 ("146", "afafd7"), 197 ("147", "afafff"), 198 ("148", "afd700"), 199 ("149", "afd75f"), 200 ("150", "afd787"), 201 ("151", "afd7af"), 202 ("152", "afd7d7"), 203 ("153", "afd7ff"), 204 ("154", "afff00"), 205 ("155", "afff5f"), 206 ("156", "afff87"), 207 ("157", "afffaf"), 208 ("158", "afffd7"), 209 ("159", "afffff"), 210 ("160", "d70000"), 211 ("161", "d7005f"), 212 ("162", "d70087"), 213 ("163", "d700af"), 214 ("164", "d700d7"), 215 ("165", "d700ff"), 216 ("166", "d75f00"), 217 ("167", "d75f5f"), 218 ("168", "d75f87"), 219 ("169", "d75faf"), 220 ("170", "d75fd7"), 221 ("171", "d75fff"), 222 ("172", "d78700"), 223 ("173", "d7875f"), 224 ("174", "d78787"), 225 ("175", "d787af"), 226 ("176", "d787d7"), 227 ("177", "d787ff"), 228 ("178", "d7af00"), 229 ("179", "d7af5f"), 230 ("180", "d7af87"), 231 ("181", "d7afaf"), 232 ("182", "d7afd7"), 233 ("183", "d7afff"), 234 ("184", "d7d700"), 235 ("185", "d7d75f"), 236 ("186", "d7d787"), 237 ("187", "d7d7af"), 238 ("188", "d7d7d7"), 239 ("189", "d7d7ff"), 240 ("190", "d7ff00"), 241 ("191", "d7ff5f"), 242 ("192", "d7ff87"), 243 ("193", "d7ffaf"), 244 ("194", "d7ffd7"), 245 ("195", "d7ffff"), 246 ("196", "ff0000"), 247 ("197", "ff005f"), 248 ("198", "ff0087"), 249 ("199", "ff00af"), 250 ("200", "ff00d7"), 251 ("201", "ff00ff"), 252 ("202", "ff5f00"), 253 ("203", "ff5f5f"), 254 ("204", "ff5f87"), 255 ("205", "ff5faf"), 256 ("206", "ff5fd7"), 257 ("207", "ff5fff"), 258 ("208", "ff8700"), 259 ("209", "ff875f"), 260 ("210", "ff8787"), 261 ("211", "ff87af"), 262 ("212", "ff87d7"), 263 ("213", "ff87ff"), 264 ("214", "ffaf00"), 265 ("215", "ffaf5f"), 266 ("216", "ffaf87"), 267 ("217", "ffafaf"), 268 ("218", "ffafd7"), 269 ("219", "ffafff"), 270 ("220", "ffd700"), 271 ("221", "ffd75f"), 272 ("222", "ffd787"), 273 ("223", "ffd7af"), 274 ("224", "ffd7d7"), 275 ("225", "ffd7ff"), 276 ("226", "ffff00"), 277 ("227", "ffff5f"), 278 ("228", "ffff87"), 279 ("229", "ffffaf"), 280 ("230", "ffffd7"), 281 ("231", "ffffff"), 282 # Gray-scale range. 283 ("232", "080808"), 284 ("233", "121212"), 285 ("234", "1c1c1c"), 286 ("235", "262626"), 287 ("236", "303030"), 288 ("237", "3a3a3a"), 289 ("238", "444444"), 290 ("239", "4e4e4e"), 291 ("240", "585858"), 292 ("241", "626262"), 293 ("242", "6c6c6c"), 294 ("243", "767676"), 295 ("244", "808080"), 296 ("245", "8a8a8a"), 297 ("246", "949494"), 298 ("247", "9e9e9e"), 299 ("248", "a8a8a8"), 300 ("249", "b2b2b2"), 301 ("250", "bcbcbc"), 302 ("251", "c6c6c6"), 303 ("252", "d0d0d0"), 304 ("253", "dadada"), 305 ("254", "e4e4e4"), 306 ("255", "eeeeee"), 307 ] 308 309 310def _str2hex(hexstr): 311 return int(hexstr, 16) 312 313 314def _strip_hash(rgb): 315 # Strip leading `#` if exists. 316 if rgb.startswith("#"): 317 rgb = rgb.lstrip("#") 318 return rgb 319 320 321@lazyobject 322def SHORT_TO_RGB(): 323 return dict(CLUT) 324 325 326@lazyobject 327def RGB_TO_SHORT(): 328 return {v: k for k, v in SHORT_TO_RGB.items()} 329 330 331def short2rgb(short): 332 return SHORT_TO_RGB[short] 333 334 335def rgb_to_256(rgb): 336 """Find the closest ANSI 256 approximation to the given RGB value. 337 338 >>> rgb2short('123456') 339 ('23', '005f5f') 340 >>> rgb2short('ffffff') 341 ('231', 'ffffff') 342 >>> rgb2short('0DADD6') # vimeo logo 343 ('38', '00afd7') 344 345 Parameters 346 ---------- 347 rgb : Hex code representing an RGB value, eg, 'abcdef' 348 349 Returns 350 ------- 351 String between 0 and 255, compatible with xterm. 352 """ 353 rgb = rgb.lstrip("#") 354 if len(rgb) == 0: 355 return "0", "000000" 356 incs = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff) 357 # Break 6-char RGB code into 3 integer vals. 358 parts = rgb_to_ints(rgb) 359 res = [] 360 for part in parts: 361 i = 0 362 while i < len(incs) - 1: 363 s, b = incs[i], incs[i + 1] # smaller, bigger 364 if s <= part <= b: 365 s1 = abs(s - part) 366 b1 = abs(b - part) 367 if s1 < b1: 368 closest = s 369 else: 370 closest = b 371 res.append(closest) 372 break 373 i += 1 374 res = "".join([("%02.x" % i) for i in res]) 375 equiv = RGB_TO_SHORT[res] 376 return equiv, res 377 378 379rgb2short = rgb_to_256 380 381 382@lazyobject 383def RE_RGB3(): 384 return re.compile(r"(.)(.)(.)") 385 386 387@lazyobject 388def RE_RGB6(): 389 return re.compile(r"(..)(..)(..)") 390 391 392def rgb_to_ints(rgb): 393 if len(rgb) == 6: 394 return tuple([int(h, 16) for h in RE_RGB6.split(rgb)[1:4]]) 395 else: 396 return tuple([int(h * 2, 16) for h in RE_RGB3.split(rgb)[1:4]]) 397 398 399def color_dist(x, y): 400 return math.sqrt((x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2 + (x[2] - y[2]) ** 2) 401 402 403def find_closest_color(x, palette): 404 return min(sorted(palette.keys())[::-1], key=lambda k: color_dist(x, palette[k])) 405 406 407def make_palette(strings): 408 """Makes a color palette from a collection of strings.""" 409 palette = {} 410 for s in strings: 411 while "#" in s: 412 _, t = s.split("#", 1) 413 t, _, s = t.partition(" ") 414 palette[t] = rgb_to_ints(t) 415 return palette 416 417 418@deprecated(deprecated_in="0.5.10", removed_in="0.6.0") 419def make_pallete(*args, **kwargs): 420 make_palette(*args, **kwargs) 421