Code Location: git://github.com/wardi/xterm_colour_chart.gitmaster
Browse
/
Download File
xterm_colour_chart.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
#!/usr/bin/python

"""
XTerm Colour Chart

Ian Ward, 2007-2012
This file is in the Public Domain, do with it as you wish.
"""

import sys
from optparse import OptionParser

__version__ = "2.1"

#  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 urwidify(num):
    """Return an urwid palette colour name for num"""
    if num < cube_start:
        return 'h%d' % num
    if num < gray_start:
        num -= cube_start
        b, num = num % cube_size, num // cube_size
        g, num = num % cube_size, num // cube_size
        r = num % cube_size
        return '#%x%x%x' % (int_scale(cube_steps[r], 256, 16),
            int_scale(cube_steps[g], 256, 16),
            int_scale(cube_steps[b], 256, 16))
    return 'g%d' % (int_scale(gray_steps[num - gray_start], 256, 101))

def int_scale(val, val_range, out_range):
    num = int(val * (out_range-1) * 2 + (val_range-1))
    dem = ((val_range-1) * 2)
    return num // dem

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, hexadecimal, decimal, urwidmal, 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
    hexadecimal -- if True display hex palette numbers on the chart
    decimal -- if True display decimal palette numbers on the chart
    urwidmal -- if True display urwid palette colour 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 hexadecimal and cell_cols < 2:
        cell_cols = 2
    elif decimal and cell_cols < 3:
        cell_cols = 3
    elif urwidmal and cell_cols < 4:
        cell_cols = 4
    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 any((hexadecimal, decimal, urwidmal)) 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
            if hexadecimal:
                return "\x1b[48;5;%d;30m%02x%s" % (n, n, cell_pad[2:])
            elif decimal:
                return "\x1b[48;5;%d;30m%03d%s" % (n, n, cell_pad[3:])
            elif urwidmal:
                return "\x1b[48;5;%d;30m%4s%s" % (n, urwidify(n), cell_pad[4:])
        # else use gray text
        if hexadecimal:
            return "\x1b[48;5;%d;37m%02x%s" % (n, n, cell_pad[2:])
        elif decimal:
            return "\x1b[48;5;%d;37m%03d%s" % (n, n, cell_pad[3:])
        elif urwidmal:
            return "\x1b[48;5;%d;37m%4s%s" % (n, urwidify(n), cell_pad[4:])

    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", "--hex", action="store_true",
        dest="hexadecimal", default=False,
        help="display hex colour numbers on chart")
    parser.add_option("-d", "--decimal", action="store_true",
        dest="decimal", default=False,
        help="display decimal colour numbers on chart")
    parser.add_option("-u", "--urwid", action="store_true",
        dest="urwidmal", default=False,
        help="display urwid palette colour 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.hexadecimal,
            options.decimal, options.urwidmal, options.columns, options.rows)



if __name__ == '__main__':
    main()