Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python
- """
- XTerm Colour Chart 2.0
- Ian Ward, 2007
- This file is in the Public Domain, do with it as you wish.
- """
- import sys
- from optparse import OptionParser
- __version__ = "2.0"
- # Colour charts
- # -------------
- # Anm - colour cube colour where A is a letter between "a" and "f" and
- # n and m are numbers between 0 and 5. eg. "a00" is the one corner
- # of the cube and "f55" is the opposite corner. The first coordinate
- # is given as a letter to help distinguish the boundaries between
- # colours in the charts. In 88-colour mode only values "a" through
- # "d" and 0 through 3 are used.
- # .nn - basic colour where nn is between 00 and 15.
- # +nn - gray colour where nn is between 01 and 24 for 256-colour mode
- # or between 01 and 08 for 88-colour mode.
- whale_shape_left = """
- e04d04c04b04
- e03d03c03b03
- e02d02c02b02
- e01d01c01b01
- e00d00c00b00a00a01a02a03a04a05b05c05d05e05f05f04f03f02f01f00
- e10d10c10b10a10a11a12a13a14a15b15c15d15e15f15f14f13f12f11f10
- e20d20c20b20a20a21a22a23a24a25b25c25d25e25f25f24f23f22f21f20
- e30d30c30b30a30a31a32a33a34a35b35c35d35e35f35f34f33f32f31f30
- e40d40c40b40a40a41a42a43a44a45b45c45d45e45f45f44f43f42f41f40
- e50d50c50b50a50a51a52a53a54a55b55c55d55e55f55f54f53f52f51f50
- b54c54d54e54
- b53c53d53e53
- .00.01.02.03.04.05.06.07 b52c52d52e52
- .08.09.10.11.12.13.14.15 b51c51d51e51
- """
- whale_shape_right = """
- d13c13
- d12c12
- d11c11b11b12b13b14c14d14e14e13e12e11
- d21c21b21b22b23b24c24d24e24e23e22e21
- d31c31b31b32b33b34c34d34e34e33e32e31
- d41c41b41b42b43b44c44d44e44e43e42e41
- c43d43
- c42d42
- c22c23d23d22
- c32c33d33d32
- +12+11+10+09+08+07+06+05+04+03+02+01
- +13+14+15+16+17+18+19+20+21+22+23+24
- """
- # join left and right whales
- whale_shape = "\n".join([l.ljust(63)+r for l,r in
- zip(whale_shape_left.split("\n"), whale_shape_right.split("\n"))])
- whale_shape_88 = """
- c02b02 b11b12c12c11
- c01b01 b21b22c22c21
- c00b00a00a01a02a03b03c03d03d02d01d00
- c10b10a10a11a12a13b13c13d13d12d11d10 +08+07+06+05+04+03+02+01
- c20b20a20a21a22a23b23c23d23d22d21d20
- c30b30a30a31a32a33b33c33d33d32d31d30
- b32c32 .00.01.02.03.04.05.06.07
- b31c31 .08.09.10.11.12.13.14.15
- """
- cloud_shape = """
- .00.01.02.03.04.05.06.07 c12c13 d13d12
- .08.09.10.11.12.13.14.15 d11c11b11b12b13b14c14d14e14e13e12e11
- d21c21b21b22b23b24c24d24e24e23e22e21
- e31d31c31b31b32b33b34c34d34e34e33e32
- c22c23d23d22 e41d41c41b41b42b43b44c44d44e44e43e42 +01+24
- d32c32c33d33 d42c42 c43d43 +02+23
- +03+22
- c02c03 d03d02 +04+21
- d01c01 b01b02b03b04 c04d04 e04e03e02e01 +05+20
- e00d00c00b00a00a01a02a03a04a05b05c05d05e05f05f04f03f02f01f00 +06+19
- e10d10c10b10a10a11a12a13a14a15b15c15d15e15f15f14f13f12f11f10 +07+18
- e20d20c20b20a20a21a22a23a24a25b25c25d25e25f25f24f23f22f21f20 +08+17
- f30e30d30c30b30a30a31a32a33a34a35b35c35d35e35f35f34f33f32f31 +09+16
- f40e40d40c40b40a40a41a42a43a44a45b45c45d45e45f45f44f43f42f41 +10+15
- f50e50d50c50b50a50a51a52a53a54a55b55c55d55e55f55f54f53f52f51 +11+14
- e51d51c51b51 b52b53 b54c54d54e54 e53e52 +12+13
- d52c52 c53d53
- """
- cloud_shape_88 = """
- b11b12c12c11
- c21b21b22c22 b01b02 c02c01
- c00b00a00a01a02a03b03c03d03d02d01d00
- +08+07+06+05+04+03+02+01 c10b10a10a11a12a13b13c13d13d12d11d10
- d20c20b20a20a21a22a23b23c23d23d22d21
- .00.01.02.03.04.05.06.07 d30c30b30a30a31a32a33b33c33d33d32d31
- .08.09.10.11.12.13.14.15 c31b31 b32c32
- """
- slices = """
- a00a01a02a03a04a05 c05c04c03c02c01c00 e00e01e02e03e04e05 +01+24 .00.08
- a10a11a12a13a14a15 c15c14c13c12c11c10 e10e11e12e13e14e15 +02+23 .01.09
- a20a21a22a23a24a25 c25c24c23c22c21c20 e20e21e22e23e24e25 +03+22 .02.10
- a30a31a32a33a34a35 c35c34c33c32c31c30 e30e31e32e33e34e35 +04+21 .03.11
- a40a41a42a43a44a45 c45c44c43c42c41c40 e40e41e42e43e44e45 +05+20 .04.12
- a50a51a52a53a54a55 c55c54c53c52c51c50 e50e51e52e53e54e55 +06+19 .05.13
- b50b51b52b53b54b55 d55d54d53d52d51d50 f50f51f52f53f54f55 +07+18 .06.14
- b40b41b42b43b44b45 d45d44d43d42d41d40 f40f41f42f43f44f45 +08+17 .07.15
- b30b31b32b33b34b35 d35d34d33d32d31d30 f30f31f32f33f34f35 +09+16
- b20b21b22b23b24b25 d25d24d23d22d21d20 f20f21f22f23f24f25 +10+15
- b10b11b12b13b14b15 d15d14d13d12d11d10 f10f11f12f13f14f15 +11+14
- b00b01b02b03b04b05 d05d04d03d02d01d00 f00f01f02f03f04f05 +12+13
- """
- slices_88 = """
- a00a01a02a03 c03c02c01c00 +01 .00.08
- a10a11a12a13 c13c12c11c10 +02 .01.09
- a20a21a22a23 c23c22c21c20 +03 .02.10
- a30a31a32a33 c33c32c31c30 +04 .03.11
- b30b31b32b33 d33d32d31d30 +05 .04.12
- b20b21b22b23 d23d22d21d20 +06 .05.13
- b10b11b12b13 d13d12d11d10 +07 .06.14
- b00b01b02b03 d03d02d01d00 +08 .07.15
- """
- ribbon_left = """
- a00a01a02a03a04a05b05c05d05e05f05f04f03f02f01f00e00d00c00b00
- a10a11a12a13a14a15b15c15d15e15f15f14f13f12f11f10e10d10c10b10
- a20a21a22a23a24a25b25c25d25e25f25f24f23f22f21f20e20d20c20b20
- a30a31a32a33a34a35b35c35d35e35f35f34f33f32f31f30e30d30c30b30
- a40a41a42a43a44a45b45c45d45e45f45f44f43f42f41f40e40d40c40b40
- a50a51a52a53a54a55b55c55d55e55f55f54f53f52f51f50e50d50c50b50
- .00.01.02.03.04.05.06.07 +01+02+03+04+05+06+07+08+09+10+11
- .08.09.10.11.12.13.14.15
- """
- ribbon_right = """
- b01c01d01e01e02e03e04d04c04b04b03c03d03d02c02b02
- b11c11d11e11e12e13e14d14c14b14b13c13d13d12c12b12
- b21c21d21e21e22e23e24d24c24b24b23c23d23d22c22b22
- b31c31d31e31e32e33e34d34c34b34b33c33d33d32c32b32
- b41c41d41e41e42e43e44d44c44b44b43c43d43d42c42b42
- b51c51d51e51e52e53e54d54c54b54b53c53d53d52c52b52
- +12+13+14+15+16+17+18+19+20+21+22+23+24
- """
- ribbon = "\n".join([l+r for l,r in
- zip(ribbon_left.split("\n"), ribbon_right.split("\n"))])
- ribbon_88 = """
- a00a01a02a03b03c03d03d02d01d00c00c01c02b02b01b00
- a10a11a12a13b13c13d13d12d11d10c10c11c12b12b11b10
- a20a21a22a23b23c23d23d22d21d20c20c21c22b22b21b20
- a30a31a32a33b33c33d33d32d31d30c30c31c32b32b31b30
- .00.01.02.03.04.05.06.07 +01+02+03+04+05+06+07+08
- .08.09.10.11.12.13.14.15
- """
- cow_shape_left = """
- +13+14+15+16+17+18+19+20+21+22+23+24 c01 e01
- +12+11+10+09+08+07+06+05+04+03+02+01 b02c02d02e02f02
- b03c03d03e03f03f13f23
- d01 b01 b04c04d04e04f04f14f24
- f01f00e00d00c00b00a00a01a02a03a04a05b05c05d05e05f05f15f25
- f12f11f10e10d10c10b10a10a11a12a13a14a15b15c15d15e15
- f32f22f21f20e20d20c20b20a20a21a22a23a24a25b25c25d25e25
- f42 f31f30e30d30c30b30a30a31a32a33a34a35b35c35d35e35f35
- f41f40e40d40c40b40a40a41a42a43a44a45b45c45d45e45f45
- f51f50e50d50c50b50a50a51a52a53a54a55b55c55d55e55f55
- f52 e51d51c51b51 b54c54 f54
- f53 e52d52c52b52 b53c53 f44
- f43 e53 d53 f34
- f33 e54 d54
- """
- cow_shape_right = """
- c23d23d22
- c32c33d33
- c22 d32 c12d12e12
- c13d13e13e23
- e11d11c11b11b12b13b14c14d14e14e24
- e22e21d21c21b21b22b23b24c24d24
- e32e31d31c31b31b32b33b34c34d34
- e33 d41c41b41 b44 d44
- e34 d42c42b42 c44 d43
- e44 e42 c43 e43
- e41 b43
- .00.01.02.03.04.05.06.07
- .08.09.10.11.12.13.14.15
- """
- # join left and right cows
- cow_shape = "\n".join([l.ljust(66)+r for l,r in
- zip(cow_shape_left.split("\n"), cow_shape_right.split("\n"))])
- cow_shape_88 = """
- .00.01.02.03.04.05.06.07 b12c12c11
- .08.09.10.11.12.13.14.15 b21b22c22
- b11 c21
- +01+02+03+04+05+06+07+08
- b01c01d01
- b02c02d02d12
- d00c00b00a00a01a02a03b03c03d03d13
- d11d10c10b10a10a11a12a13b13c13
- d21d20c20b20a20a21a22a23b23c23
- d22 c30b30a30 a33 c33
- d23 c31b31a31 b33 c32
- d33 d31 b32 d32
- d30 a32
- """
- charts = {
- 88: {
- 'cows': cow_shape_88,
- 'whales': whale_shape_88,
- 'slices': slices_88,
- 'ribbon': ribbon_88,
- 'clouds': cloud_shape_88,},
- 256: {
- 'cows': cow_shape,
- 'whales': whale_shape,
- 'slices': slices,
- 'ribbon': ribbon,
- 'clouds': cloud_shape,}}
- # global settings
- basic_start = 0 # first index of basic colours
- cube_start = 16 # first index of colour cube
- cube_size = 6 # one side of the colour cube
- gray_start = cube_size ** 3 + cube_start
- colours = 256
- # values copied from xterm 256colres.h:
- cube_steps = 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff
- gray_steps = (0x08, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e, 0x58, 0x62,
- 0x6c, 0x76, 0x80, 0x84, 0x94, 0x9e, 0xa8, 0xb2, 0xbc, 0xc6, 0xd0,
- 0xda, 0xe4, 0xee)
- # values copied from X11/rgb.txt and XTerm-col.ad:
- basic_colours = ((0,0,0), (205, 0, 0), (0, 205, 0), (205, 205, 0),
- (0, 0, 238), (205, 0, 205), (0, 205, 205), (229, 229, 229),
- (127, 127, 127), (255, 0, 0), (0, 255, 0), (255, 255, 0),
- (0x5c, 0x5c, 0xff), (255, 0, 255), (0, 255, 255), (255, 255, 255))
- def set_88_colour_mode():
- """Switch to 88-colour mode."""
- global cube_size, gray_start, colours, cube_steps, gray_steps
- cube_size = 4
- gray_start = cube_size ** 3 + cube_start
- colours = 88
- # values copied from xterm 88colres.h:
- cube_steps = 0x00, 0x8b, 0xcd, 0xff
- gray_steps = 0x2e, 0x5c, 0x73, 0x8b, 0xa2, 0xb9, 0xd0, 0xe7
- def error(e):
- """Report an error to the user."""
- sys.stderr.write(e+"\n")
- def cube_vals(n):
- """Return the cube coordinates for colour-number n."""
- assert n>=cube_start and n<gray_start
- val = n-cube_start
- c = val % cube_size
- val = val / cube_size
- b = val % cube_size
- a = val / cube_size
- return a, b, c
- def n_to_rgb(n):
- """Return the red, green and blue components of colour-number n.
- Components are between 0 and 255."""
- if n<cube_start:
- return basic_colours[n-basic_start]
- if n<gray_start:
- return [cube_steps[v] for v in cube_vals(n)]
- return (gray_steps[n-gray_start],) * 3
- def n_to_gray(n):
- """Return an approximate desaturated value for colour-number n.
- Value is between 0.0 and 255.0."""
- r, g, b = n_to_rgb(n)
- return 0.3*r + 0.59*g + 0.11*b
- def n_to_prt(n):
- """Convert a colour number to the format used in the colour charts."""
- if n >= gray_start:
- return "+%02d" % (n-gray_start+1)
- elif n >= cube_start:
- a, b, c = cube_vals(n)
- return "%s%s%s" % (chr(ord('a')+a), chr(ord('0')+b), chr(ord('0')+c))
- else:
- return ".%02d not found" % (n-basic_start)
- def prt_to_n(prt):
- """Convert a colour chart cell to a colour number."""
- assert len(prt)==3
- if prt == ' ':
- n = -1
- elif prt[0] == '.':
- val = int(prt[1:])
- assert val>=0 and val<cube_start
- n = basic_start + val
- elif prt[0] == '+':
- val = int(prt[1:])-1
- assert val>=0 and val<colours-gray_start, prt
- n = gray_start + val
- else:
- a = ord(prt[0])-ord('a')
- assert a>=0 and a<cube_size, prt
- b = ord(prt[1])-ord('0')
- assert b>=0 and b<cube_size, prt
- c = ord(prt[2])-ord('0')
- assert c>=0 and c<cube_size, prt
- n = cube_start + (a*cube_size + b)*cube_size + c
- return n
- def distance(n1, n2):
- """Calculate the distance between colours in the colour cube.
- Distance is absolute cube coordinates, not actual colour distance.
- Return -1 if one of the colours is not part of the colour cube."""
- if n1<cube_start or n1>=gray_start:
- return -1
- if n2<cube_start or n2>=gray_start:
- return -1
- a1, b1, c1 = cube_vals(n1)
- a2, b2, c2 = cube_vals(n2)
- return abs(a1-a2)+abs(b1-b2)+abs(c1-c2)
- def parse_chart(chart):
- """Parse a colour chart passed in as a string."""
- chart = chart.rstrip()
- found = set()
- oall = [] # the complete chart output
- for ln in chart.split('\n'):
- oln = [] # the current line of output
- ln = ln.rstrip()
- if not oall and not ln:
- # remove blank lines from top of chart
- continue
- for loff in range(0, len(ln), 3):
- prt = ln[loff:loff+3]
- if not prt:
- continue
- n = prt_to_n(prt)
- if n>=0 and n in found:
- error("duplicate entry %s found" % prt)
- found.add(n)
- if oall and len(oall[-1])>len(oln): # compare distance above
- nabove = oall[-1][len(oln)]
- if distance(nabove, n)>1:
- error("entry %s found above %s" % (n_to_prt(nabove), prt))
- if oln: # compare distance to left
- nleft = oln[-1]
- if distance(nleft, n)>1:
- error("entry %s found left of %s" % (n_to_prt(nleft), prt))
- oln.append(n)
- oall.append(oln)
- # make sure all colours were included in the chart
- for n in range(colours):
- if n in found:
- continue
- error("entry %s not found" % n_to_prt(n))
- return oall
- def draw_chart(chart, origin, angle, numbers, cell_cols, cell_rows):
- """Draw a colour chart on the screen.
- chart -- chart data parsed by parse_chart()
- origin -- 0..7 origin of colour cube
- angle -- 0..5 rotation angle of colour cube
- numbers -- if True display hex palette numbers on the chart
- cell_cols -- number of screen columns per cell
- cell_rows -- number of screen rows per cell
- """
- amap = [(0,1,2), (1,2,0), (2,0,1), (0,2,1), (1,0,2), (2,1,0)][angle]
- omap = [(1,1,1), (1,1,-1), (1,-1,-1), (1,-1,1),
- (-1,-1,1), (-1,-1,-1), (-1,1,-1), (-1,1,1)][origin]
- if numbers and cell_cols<2:
- cell_cols=2
- cell_pad = " "*cell_cols
- def transform_block(n, row):
- v = cube_vals(n)
- v = [(int(om/2) + om * n) % cube_size for n, om in zip(v, omap)]
- r, g, b = v[amap[0]], v[amap[1]], v[amap[2]]
- vtrans = (r*cube_size + g)*cube_size + b + cube_start
- return block(vtrans, row)
- def block(n, row):
- if not numbers or row!=cell_rows-1:
- return "\x1b[48;5;%dm%s" % (n, cell_pad)
- y = n_to_gray(n)
- if y>0x30:
- # use black text
- return "\x1b[48;5;%d;30m%02x%s" % (n, n, cell_pad[2:])
- # else use gray text
- return "\x1b[48;5;%d;37m%02x%s" % (n, n, cell_pad[2:])
- def blank():
- return "\x1b[0m%s" % (cell_pad,)
- for ln in chart:
- for row in range(cell_rows):
- out = []
- for n in ln:
- if n<0:
- out.append(blank())
- elif n<cube_start:
- out.append(block(n, row))
- elif n<gray_start:
- out.append(transform_block(n, row))
- else:
- out.append(block(n, row))
- print "".join(out) + "\x1b[0m"
- def reset_palette():
- """Reset the terminal palette."""
- reset = ["%d;rgb:%02x/%02x/%02x" % ((n,) + tuple(n_to_rgb(n)))
- for n in range(colours)]
- sys.stdout.write("\x1b]4;"+";".join(reset)+"\x1b\\")
- def main():
- parser = OptionParser(usage="%prog [options] [chart names]",
- version="%prog "+__version__)
- parser.add_option("-8", "--88-colours", action="store_true",
- dest="colours_88", default=False,
- help="use 88-colour mode [default: 256-colour mode]")
- parser.add_option("-l", "--list-charts", action="store_true",
- dest="list_charts", default=False,
- help="list available charts")
- parser.add_option("-o", "--origin", dest="origin", type="int",
- default=0, metavar="NUM",
- help="set the origin of the colour cube: 0-7 [default: %default]")
- parser.add_option("-a", "--angle", dest="angle", type="int",
- default=0, metavar="NUM",
- help="set the angle of the colour cube: 0-5 [default: %default]")
- parser.add_option("-n", "--numbers", action="store_true",
- dest="numbers", default=False,
- help="display hex colour numbers on chart")
- parser.add_option("-x", "--cell-columns", dest="columns", type="int",
- default=2, metavar="COLS",
- help="set the number of columns for drawing each colour cell "
- "[default: %default]")
- parser.add_option("-y", "--cell-rows", dest="rows", type="int",
- default=1, metavar="ROWS",
- help="set the number of rows for drawing each colour cell "
- "[default: %default]")
- parser.add_option("-r", "--reset-palette", action="store_true",
- dest="reset_palette", default=False,
- help="reset the colour palette before displaying chart, "
- "this option may be used to switch between 88 and 256-colour "
- "modes in xterm")
- options, args = parser.parse_args()
- if options.origin<0 or options.origin>7:
- error("Invalid origin value specified!")
- sys.exit(2)
- if options.angle<0 or options.angle>5:
- error("Invalid angle value specified!")
- sys.exit(2)
- if options.columns < 1:
- error("Invalid number of columns specified!")
- if options.rows < 1:
- error("Invalid number of rows specified!")
- if options.colours_88:
- set_88_colour_mode()
- if options.list_charts:
- print "Charts available in %d-colour mode:" % colours
- for cname in charts[colours].keys():
- print " "+cname
- sys.exit(0)
- if options.reset_palette:
- reset_palette()
- if not args:
- args = ["whales"] # default chart
- first = True
- for cname in args:
- if not first:
- print
- first = False
- if cname not in charts[colours]:
- error("Chart %r not found!" % cname)
- continue
- chart = parse_chart(charts[colours][cname])
- draw_chart(chart, options.origin, options.angle, options.numbers,
- options.columns, options.rows)
- if __name__ == '__main__':
- main()
Add Comment
Please, Sign In to add comment