dotfiles

Configuration for the software I use.
git clone https://git.jaderune.net/jbauer/dotfiles
Log | Files | Refs | README | LICENSE

convert_hex_xterm (9403B)


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