Guest User

Untitled

a guest
Apr 24th, 2018
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.34 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. """
  4. XTerm Colour Chart 2.0
  5.  
  6. Ian Ward, 2007
  7. This file is in the Public Domain, do with it as you wish.
  8. """
  9.  
  10. import sys
  11. from optparse import OptionParser
  12.  
  13. __version__ = "2.0"
  14.  
  15. # Colour charts
  16. # -------------
  17. # Anm - colour cube colour where A is a letter between "a" and "f" and
  18. # n and m are numbers between 0 and 5. eg. "a00" is the one corner
  19. # of the cube and "f55" is the opposite corner. The first coordinate
  20. # is given as a letter to help distinguish the boundaries between
  21. # colours in the charts. In 88-colour mode only values "a" through
  22. # "d" and 0 through 3 are used.
  23. # .nn - basic colour where nn is between 00 and 15.
  24. # +nn - gray colour where nn is between 01 and 24 for 256-colour mode
  25. # or between 01 and 08 for 88-colour mode.
  26.  
  27. whale_shape_left = """
  28. e04d04c04b04
  29. e03d03c03b03
  30. e02d02c02b02
  31. e01d01c01b01
  32. e00d00c00b00a00a01a02a03a04a05b05c05d05e05f05f04f03f02f01f00
  33. e10d10c10b10a10a11a12a13a14a15b15c15d15e15f15f14f13f12f11f10
  34. e20d20c20b20a20a21a22a23a24a25b25c25d25e25f25f24f23f22f21f20
  35. e30d30c30b30a30a31a32a33a34a35b35c35d35e35f35f34f33f32f31f30
  36. e40d40c40b40a40a41a42a43a44a45b45c45d45e45f45f44f43f42f41f40
  37. e50d50c50b50a50a51a52a53a54a55b55c55d55e55f55f54f53f52f51f50
  38. b54c54d54e54
  39. b53c53d53e53
  40. .00.01.02.03.04.05.06.07 b52c52d52e52
  41. .08.09.10.11.12.13.14.15 b51c51d51e51
  42. """
  43.  
  44. whale_shape_right = """
  45. d13c13
  46. d12c12
  47. d11c11b11b12b13b14c14d14e14e13e12e11
  48. d21c21b21b22b23b24c24d24e24e23e22e21
  49. d31c31b31b32b33b34c34d34e34e33e32e31
  50. d41c41b41b42b43b44c44d44e44e43e42e41
  51. c43d43
  52. c42d42
  53. c22c23d23d22
  54. c32c33d33d32
  55.  
  56.  
  57. +12+11+10+09+08+07+06+05+04+03+02+01
  58. +13+14+15+16+17+18+19+20+21+22+23+24
  59. """
  60. # join left and right whales
  61. whale_shape = "\n".join([l.ljust(63)+r for l,r in
  62. zip(whale_shape_left.split("\n"), whale_shape_right.split("\n"))])
  63.  
  64. whale_shape_88 = """
  65. c02b02 b11b12c12c11
  66. c01b01 b21b22c22c21
  67. c00b00a00a01a02a03b03c03d03d02d01d00
  68. c10b10a10a11a12a13b13c13d13d12d11d10 +08+07+06+05+04+03+02+01
  69. c20b20a20a21a22a23b23c23d23d22d21d20
  70. c30b30a30a31a32a33b33c33d33d32d31d30
  71. b32c32 .00.01.02.03.04.05.06.07
  72. b31c31 .08.09.10.11.12.13.14.15
  73.  
  74. """
  75.  
  76. cloud_shape = """
  77. .00.01.02.03.04.05.06.07 c12c13 d13d12
  78. .08.09.10.11.12.13.14.15 d11c11b11b12b13b14c14d14e14e13e12e11
  79. d21c21b21b22b23b24c24d24e24e23e22e21
  80. e31d31c31b31b32b33b34c34d34e34e33e32
  81. c22c23d23d22 e41d41c41b41b42b43b44c44d44e44e43e42 +01+24
  82. d32c32c33d33 d42c42 c43d43 +02+23
  83. +03+22
  84. c02c03 d03d02 +04+21
  85. d01c01 b01b02b03b04 c04d04 e04e03e02e01 +05+20
  86. e00d00c00b00a00a01a02a03a04a05b05c05d05e05f05f04f03f02f01f00 +06+19
  87. e10d10c10b10a10a11a12a13a14a15b15c15d15e15f15f14f13f12f11f10 +07+18
  88. e20d20c20b20a20a21a22a23a24a25b25c25d25e25f25f24f23f22f21f20 +08+17
  89. f30e30d30c30b30a30a31a32a33a34a35b35c35d35e35f35f34f33f32f31 +09+16
  90. f40e40d40c40b40a40a41a42a43a44a45b45c45d45e45f45f44f43f42f41 +10+15
  91. f50e50d50c50b50a50a51a52a53a54a55b55c55d55e55f55f54f53f52f51 +11+14
  92. e51d51c51b51 b52b53 b54c54d54e54 e53e52 +12+13
  93. d52c52 c53d53
  94. """
  95.  
  96. cloud_shape_88 = """
  97. b11b12c12c11
  98. c21b21b22c22 b01b02 c02c01
  99. c00b00a00a01a02a03b03c03d03d02d01d00
  100. +08+07+06+05+04+03+02+01 c10b10a10a11a12a13b13c13d13d12d11d10
  101. d20c20b20a20a21a22a23b23c23d23d22d21
  102. .00.01.02.03.04.05.06.07 d30c30b30a30a31a32a33b33c33d33d32d31
  103. .08.09.10.11.12.13.14.15 c31b31 b32c32
  104. """
  105.  
  106. slices = """
  107. a00a01a02a03a04a05 c05c04c03c02c01c00 e00e01e02e03e04e05 +01+24 .00.08
  108. a10a11a12a13a14a15 c15c14c13c12c11c10 e10e11e12e13e14e15 +02+23 .01.09
  109. a20a21a22a23a24a25 c25c24c23c22c21c20 e20e21e22e23e24e25 +03+22 .02.10
  110. a30a31a32a33a34a35 c35c34c33c32c31c30 e30e31e32e33e34e35 +04+21 .03.11
  111. a40a41a42a43a44a45 c45c44c43c42c41c40 e40e41e42e43e44e45 +05+20 .04.12
  112. a50a51a52a53a54a55 c55c54c53c52c51c50 e50e51e52e53e54e55 +06+19 .05.13
  113. b50b51b52b53b54b55 d55d54d53d52d51d50 f50f51f52f53f54f55 +07+18 .06.14
  114. b40b41b42b43b44b45 d45d44d43d42d41d40 f40f41f42f43f44f45 +08+17 .07.15
  115. b30b31b32b33b34b35 d35d34d33d32d31d30 f30f31f32f33f34f35 +09+16
  116. b20b21b22b23b24b25 d25d24d23d22d21d20 f20f21f22f23f24f25 +10+15
  117. b10b11b12b13b14b15 d15d14d13d12d11d10 f10f11f12f13f14f15 +11+14
  118. b00b01b02b03b04b05 d05d04d03d02d01d00 f00f01f02f03f04f05 +12+13
  119. """
  120.  
  121.  
  122. slices_88 = """
  123. a00a01a02a03 c03c02c01c00 +01 .00.08
  124. a10a11a12a13 c13c12c11c10 +02 .01.09
  125. a20a21a22a23 c23c22c21c20 +03 .02.10
  126. a30a31a32a33 c33c32c31c30 +04 .03.11
  127. b30b31b32b33 d33d32d31d30 +05 .04.12
  128. b20b21b22b23 d23d22d21d20 +06 .05.13
  129. b10b11b12b13 d13d12d11d10 +07 .06.14
  130. b00b01b02b03 d03d02d01d00 +08 .07.15
  131. """
  132.  
  133.  
  134. ribbon_left = """
  135. a00a01a02a03a04a05b05c05d05e05f05f04f03f02f01f00e00d00c00b00
  136. a10a11a12a13a14a15b15c15d15e15f15f14f13f12f11f10e10d10c10b10
  137. a20a21a22a23a24a25b25c25d25e25f25f24f23f22f21f20e20d20c20b20
  138. a30a31a32a33a34a35b35c35d35e35f35f34f33f32f31f30e30d30c30b30
  139. a40a41a42a43a44a45b45c45d45e45f45f44f43f42f41f40e40d40c40b40
  140. a50a51a52a53a54a55b55c55d55e55f55f54f53f52f51f50e50d50c50b50
  141.  
  142. .00.01.02.03.04.05.06.07 +01+02+03+04+05+06+07+08+09+10+11
  143. .08.09.10.11.12.13.14.15
  144. """
  145.  
  146. ribbon_right = """
  147. b01c01d01e01e02e03e04d04c04b04b03c03d03d02c02b02
  148. b11c11d11e11e12e13e14d14c14b14b13c13d13d12c12b12
  149. b21c21d21e21e22e23e24d24c24b24b23c23d23d22c22b22
  150. b31c31d31e31e32e33e34d34c34b34b33c33d33d32c32b32
  151. b41c41d41e41e42e43e44d44c44b44b43c43d43d42c42b42
  152. b51c51d51e51e52e53e54d54c54b54b53c53d53d52c52b52
  153.  
  154. +12+13+14+15+16+17+18+19+20+21+22+23+24
  155.  
  156. """
  157.  
  158. ribbon = "\n".join([l+r for l,r in
  159. zip(ribbon_left.split("\n"), ribbon_right.split("\n"))])
  160.  
  161. ribbon_88 = """
  162. a00a01a02a03b03c03d03d02d01d00c00c01c02b02b01b00
  163. a10a11a12a13b13c13d13d12d11d10c10c11c12b12b11b10
  164. a20a21a22a23b23c23d23d22d21d20c20c21c22b22b21b20
  165. a30a31a32a33b33c33d33d32d31d30c30c31c32b32b31b30
  166.  
  167. .00.01.02.03.04.05.06.07 +01+02+03+04+05+06+07+08
  168. .08.09.10.11.12.13.14.15
  169. """
  170.  
  171. cow_shape_left = """
  172. +13+14+15+16+17+18+19+20+21+22+23+24 c01 e01
  173. +12+11+10+09+08+07+06+05+04+03+02+01 b02c02d02e02f02
  174. b03c03d03e03f03f13f23
  175. d01 b01 b04c04d04e04f04f14f24
  176. f01f00e00d00c00b00a00a01a02a03a04a05b05c05d05e05f05f15f25
  177. f12f11f10e10d10c10b10a10a11a12a13a14a15b15c15d15e15
  178. f32f22f21f20e20d20c20b20a20a21a22a23a24a25b25c25d25e25
  179. f42 f31f30e30d30c30b30a30a31a32a33a34a35b35c35d35e35f35
  180. f41f40e40d40c40b40a40a41a42a43a44a45b45c45d45e45f45
  181. f51f50e50d50c50b50a50a51a52a53a54a55b55c55d55e55f55
  182. f52 e51d51c51b51 b54c54 f54
  183. f53 e52d52c52b52 b53c53 f44
  184. f43 e53 d53 f34
  185. f33 e54 d54
  186. """
  187.  
  188. cow_shape_right = """
  189. c23d23d22
  190. c32c33d33
  191. c22 d32 c12d12e12
  192. c13d13e13e23
  193. e11d11c11b11b12b13b14c14d14e14e24
  194. e22e21d21c21b21b22b23b24c24d24
  195. e32e31d31c31b31b32b33b34c34d34
  196. e33 d41c41b41 b44 d44
  197. e34 d42c42b42 c44 d43
  198. e44 e42 c43 e43
  199. e41 b43
  200.  
  201. .00.01.02.03.04.05.06.07
  202. .08.09.10.11.12.13.14.15
  203. """
  204. # join left and right cows
  205. cow_shape = "\n".join([l.ljust(66)+r for l,r in
  206. zip(cow_shape_left.split("\n"), cow_shape_right.split("\n"))])
  207.  
  208. cow_shape_88 = """
  209. .00.01.02.03.04.05.06.07 b12c12c11
  210. .08.09.10.11.12.13.14.15 b21b22c22
  211. b11 c21
  212. +01+02+03+04+05+06+07+08
  213. b01c01d01
  214. b02c02d02d12
  215. d00c00b00a00a01a02a03b03c03d03d13
  216. d11d10c10b10a10a11a12a13b13c13
  217. d21d20c20b20a20a21a22a23b23c23
  218. d22 c30b30a30 a33 c33
  219. d23 c31b31a31 b33 c32
  220. d33 d31 b32 d32
  221. d30 a32
  222. """
  223.  
  224. charts = {
  225. 88: {
  226. 'cows': cow_shape_88,
  227. 'whales': whale_shape_88,
  228. 'slices': slices_88,
  229. 'ribbon': ribbon_88,
  230. 'clouds': cloud_shape_88,},
  231. 256: {
  232. 'cows': cow_shape,
  233. 'whales': whale_shape,
  234. 'slices': slices,
  235. 'ribbon': ribbon,
  236. 'clouds': cloud_shape,}}
  237.  
  238. # global settings
  239.  
  240. basic_start = 0 # first index of basic colours
  241. cube_start = 16 # first index of colour cube
  242. cube_size = 6 # one side of the colour cube
  243. gray_start = cube_size ** 3 + cube_start
  244. colours = 256
  245. # values copied from xterm 256colres.h:
  246. cube_steps = 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff
  247. gray_steps = (0x08, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e, 0x58, 0x62,
  248. 0x6c, 0x76, 0x80, 0x84, 0x94, 0x9e, 0xa8, 0xb2, 0xbc, 0xc6, 0xd0,
  249. 0xda, 0xe4, 0xee)
  250. # values copied from X11/rgb.txt and XTerm-col.ad:
  251. basic_colours = ((0,0,0), (205, 0, 0), (0, 205, 0), (205, 205, 0),
  252. (0, 0, 238), (205, 0, 205), (0, 205, 205), (229, 229, 229),
  253. (127, 127, 127), (255, 0, 0), (0, 255, 0), (255, 255, 0),
  254. (0x5c, 0x5c, 0xff), (255, 0, 255), (0, 255, 255), (255, 255, 255))
  255.  
  256. def set_88_colour_mode():
  257. """Switch to 88-colour mode."""
  258. global cube_size, gray_start, colours, cube_steps, gray_steps
  259. cube_size = 4
  260. gray_start = cube_size ** 3 + cube_start
  261. colours = 88
  262. # values copied from xterm 88colres.h:
  263. cube_steps = 0x00, 0x8b, 0xcd, 0xff
  264. gray_steps = 0x2e, 0x5c, 0x73, 0x8b, 0xa2, 0xb9, 0xd0, 0xe7
  265.  
  266.  
  267. def error(e):
  268. """Report an error to the user."""
  269. sys.stderr.write(e+"\n")
  270.  
  271. def cube_vals(n):
  272. """Return the cube coordinates for colour-number n."""
  273. assert n>=cube_start and n<gray_start
  274. val = n-cube_start
  275. c = val % cube_size
  276. val = val / cube_size
  277. b = val % cube_size
  278. a = val / cube_size
  279. return a, b, c
  280.  
  281. def n_to_rgb(n):
  282. """Return the red, green and blue components of colour-number n.
  283. Components are between 0 and 255."""
  284. if n<cube_start:
  285. return basic_colours[n-basic_start]
  286. if n<gray_start:
  287. return [cube_steps[v] for v in cube_vals(n)]
  288. return (gray_steps[n-gray_start],) * 3
  289.  
  290. def n_to_gray(n):
  291. """Return an approximate desaturated value for colour-number n.
  292. Value is between 0.0 and 255.0."""
  293. r, g, b = n_to_rgb(n)
  294. return 0.3*r + 0.59*g + 0.11*b
  295.  
  296. def n_to_prt(n):
  297. """Convert a colour number to the format used in the colour charts."""
  298. if n >= gray_start:
  299. return "+%02d" % (n-gray_start+1)
  300. elif n >= cube_start:
  301. a, b, c = cube_vals(n)
  302. return "%s%s%s" % (chr(ord('a')+a), chr(ord('0')+b), chr(ord('0')+c))
  303. else:
  304. return ".%02d not found" % (n-basic_start)
  305.  
  306. def prt_to_n(prt):
  307. """Convert a colour chart cell to a colour number."""
  308. assert len(prt)==3
  309. if prt == ' ':
  310. n = -1
  311. elif prt[0] == '.':
  312. val = int(prt[1:])
  313. assert val>=0 and val<cube_start
  314. n = basic_start + val
  315. elif prt[0] == '+':
  316. val = int(prt[1:])-1
  317. assert val>=0 and val<colours-gray_start, prt
  318. n = gray_start + val
  319. else:
  320. a = ord(prt[0])-ord('a')
  321. assert a>=0 and a<cube_size, prt
  322. b = ord(prt[1])-ord('0')
  323. assert b>=0 and b<cube_size, prt
  324. c = ord(prt[2])-ord('0')
  325. assert c>=0 and c<cube_size, prt
  326. n = cube_start + (a*cube_size + b)*cube_size + c
  327. return n
  328.  
  329. def distance(n1, n2):
  330. """Calculate the distance between colours in the colour cube.
  331. Distance is absolute cube coordinates, not actual colour distance.
  332. Return -1 if one of the colours is not part of the colour cube."""
  333. if n1<cube_start or n1>=gray_start:
  334. return -1
  335. if n2<cube_start or n2>=gray_start:
  336. return -1
  337. a1, b1, c1 = cube_vals(n1)
  338. a2, b2, c2 = cube_vals(n2)
  339. return abs(a1-a2)+abs(b1-b2)+abs(c1-c2)
  340.  
  341. def parse_chart(chart):
  342. """Parse a colour chart passed in as a string."""
  343. chart = chart.rstrip()
  344. found = set()
  345.  
  346. oall = [] # the complete chart output
  347. for ln in chart.split('\n'):
  348. oln = [] # the current line of output
  349. ln = ln.rstrip()
  350. if not oall and not ln:
  351. # remove blank lines from top of chart
  352. continue
  353.  
  354. for loff in range(0, len(ln), 3):
  355. prt = ln[loff:loff+3]
  356. if not prt:
  357. continue
  358. n = prt_to_n(prt)
  359. if n>=0 and n in found:
  360. error("duplicate entry %s found" % prt)
  361. found.add(n)
  362. if oall and len(oall[-1])>len(oln): # compare distance above
  363. nabove = oall[-1][len(oln)]
  364. if distance(nabove, n)>1:
  365. error("entry %s found above %s" % (n_to_prt(nabove), prt))
  366. if oln: # compare distance to left
  367. nleft = oln[-1]
  368. if distance(nleft, n)>1:
  369. error("entry %s found left of %s" % (n_to_prt(nleft), prt))
  370. oln.append(n)
  371. oall.append(oln)
  372.  
  373. # make sure all colours were included in the chart
  374. for n in range(colours):
  375. if n in found:
  376. continue
  377. error("entry %s not found" % n_to_prt(n))
  378.  
  379. return oall
  380.  
  381.  
  382. def draw_chart(chart, origin, angle, numbers, cell_cols, cell_rows):
  383. """Draw a colour chart on the screen.
  384.  
  385. chart -- chart data parsed by parse_chart()
  386. origin -- 0..7 origin of colour cube
  387. angle -- 0..5 rotation angle of colour cube
  388. numbers -- if True display hex palette numbers on the chart
  389. cell_cols -- number of screen columns per cell
  390. cell_rows -- number of screen rows per cell
  391. """
  392. amap = [(0,1,2), (1,2,0), (2,0,1), (0,2,1), (1,0,2), (2,1,0)][angle]
  393. omap = [(1,1,1), (1,1,-1), (1,-1,-1), (1,-1,1),
  394. (-1,-1,1), (-1,-1,-1), (-1,1,-1), (-1,1,1)][origin]
  395.  
  396. if numbers and cell_cols<2:
  397. cell_cols=2
  398. cell_pad = " "*cell_cols
  399.  
  400. def transform_block(n, row):
  401. v = cube_vals(n)
  402. v = [(int(om/2) + om * n) % cube_size for n, om in zip(v, omap)]
  403. r, g, b = v[amap[0]], v[amap[1]], v[amap[2]]
  404. vtrans = (r*cube_size + g)*cube_size + b + cube_start
  405. return block(vtrans, row)
  406.  
  407. def block(n, row):
  408. if not numbers or row!=cell_rows-1:
  409. return "\x1b[48;5;%dm%s" % (n, cell_pad)
  410. y = n_to_gray(n)
  411. if y>0x30:
  412. # use black text
  413. return "\x1b[48;5;%d;30m%02x%s" % (n, n, cell_pad[2:])
  414. # else use gray text
  415. return "\x1b[48;5;%d;37m%02x%s" % (n, n, cell_pad[2:])
  416.  
  417. def blank():
  418. return "\x1b[0m%s" % (cell_pad,)
  419.  
  420. for ln in chart:
  421. for row in range(cell_rows):
  422. out = []
  423. for n in ln:
  424. if n<0:
  425. out.append(blank())
  426. elif n<cube_start:
  427. out.append(block(n, row))
  428. elif n<gray_start:
  429. out.append(transform_block(n, row))
  430. else:
  431. out.append(block(n, row))
  432. print "".join(out) + "\x1b[0m"
  433.  
  434. def reset_palette():
  435. """Reset the terminal palette."""
  436. reset = ["%d;rgb:%02x/%02x/%02x" % ((n,) + tuple(n_to_rgb(n)))
  437. for n in range(colours)]
  438. sys.stdout.write("\x1b]4;"+";".join(reset)+"\x1b\\")
  439.  
  440. def main():
  441. parser = OptionParser(usage="%prog [options] [chart names]",
  442. version="%prog "+__version__)
  443. parser.add_option("-8", "--88-colours", action="store_true",
  444. dest="colours_88", default=False,
  445. help="use 88-colour mode [default: 256-colour mode]")
  446. parser.add_option("-l", "--list-charts", action="store_true",
  447. dest="list_charts", default=False,
  448. help="list available charts")
  449. parser.add_option("-o", "--origin", dest="origin", type="int",
  450. default=0, metavar="NUM",
  451. help="set the origin of the colour cube: 0-7 [default: %default]")
  452. parser.add_option("-a", "--angle", dest="angle", type="int",
  453. default=0, metavar="NUM",
  454. help="set the angle of the colour cube: 0-5 [default: %default]")
  455. parser.add_option("-n", "--numbers", action="store_true",
  456. dest="numbers", default=False,
  457. help="display hex colour numbers on chart")
  458. parser.add_option("-x", "--cell-columns", dest="columns", type="int",
  459. default=2, metavar="COLS",
  460. help="set the number of columns for drawing each colour cell "
  461. "[default: %default]")
  462. parser.add_option("-y", "--cell-rows", dest="rows", type="int",
  463. default=1, metavar="ROWS",
  464. help="set the number of rows for drawing each colour cell "
  465. "[default: %default]")
  466. parser.add_option("-r", "--reset-palette", action="store_true",
  467. dest="reset_palette", default=False,
  468. help="reset the colour palette before displaying chart, "
  469. "this option may be used to switch between 88 and 256-colour "
  470. "modes in xterm")
  471.  
  472. options, args = parser.parse_args()
  473. if options.origin<0 or options.origin>7:
  474. error("Invalid origin value specified!")
  475. sys.exit(2)
  476. if options.angle<0 or options.angle>5:
  477. error("Invalid angle value specified!")
  478. sys.exit(2)
  479. if options.columns < 1:
  480. error("Invalid number of columns specified!")
  481. if options.rows < 1:
  482. error("Invalid number of rows specified!")
  483. if options.colours_88:
  484. set_88_colour_mode()
  485. if options.list_charts:
  486. print "Charts available in %d-colour mode:" % colours
  487. for cname in charts[colours].keys():
  488. print " "+cname
  489. sys.exit(0)
  490. if options.reset_palette:
  491. reset_palette()
  492.  
  493. if not args:
  494. args = ["whales"] # default chart
  495. first = True
  496. for cname in args:
  497. if not first:
  498. print
  499. first = False
  500. if cname not in charts[colours]:
  501. error("Chart %r not found!" % cname)
  502. continue
  503. chart = parse_chart(charts[colours][cname])
  504. draw_chart(chart, options.origin, options.angle, options.numbers,
  505. options.columns, options.rows)
  506.  
  507.  
  508.  
  509. if __name__ == '__main__':
  510. main()
Add Comment
Please, Sign In to add comment