RGB values of the colors in the Ansi extended colors index (17-255)

12.8k views Asked by At

My question is in general shell scripting with ansi colors but for reference I am using an Apple Mac OS X 10.9 Mavericks. I use "iTerm" terminal app as my default terminal but also checked with the built in "terminal" app as well. I use ZSH (5.0.7) as my default shell but also checked in BASH (3.2.51).

I have been trying to find out if there is a list of the RGB values for the 256 color indexed extended fore/background Ansi escape codes that are available using esc[38;5;xm and esc[48;5;xm where x is a number from 0 to 255. I have found some scripts that print out the colors as blocks (using the index) but I want to know the rgb values of each of the colors in the indexes.

Here is an example of the ansi codes in use:

printf '\e[38;5;222;48;5;238m  Hi  \e[m\n'

(\e can be replaced by \033 or \x1b)

So basically I am wondering if there is a list or agreed upon settings for these indexed colors? For example 232-255 seem to always be a gray gradient. Every site that I have found that references the extended colors pretty much just says how to use it and doesn't list any specific colors.

I found some references to X11 and an rgb.txt file which at first seemed like it was what I was looking for but they don't seem to match up to the index numbers. There are 752 colors in the file I found (most are duplicates so say 376 which is still more the 256). Also there are 50 shades of gray (100 if you count duplicates) but the Ansi indexed colors have 23 so it doesn't seem to be the same. If these in some way do contain the colors in the ansi extended color index does anyone have a list of which names are in which index?

PS. I know esc[38;2;r;g:bm can supposedly set a color using rgb values but I can't get it to work on my Mac and I am more interested in the default values for the indexed colors.

Some sites: (can only post 2 due to low rep? But I checked a lot of sites)

This one has the rgb for the standard colors but not the extended ones.

This one has a chart of the colors but not the rgb values

2

There are 2 answers

7
Adaephon On

The 256 color table and its partitioning

The color range of a 256 color terminal consists of 4 parts, often 5, in which case you actually get 258 colors:

  1. Color numbers 0 to 7 are the default terminal colors, the actual RGB value of which is not standardized and can often be configured.

  2. Color numbers 8 to 15 are the "bright" colors. Most of the time these are a lighter shade of the color with index - 8. They are also not standardized and can often be configured. Depending on terminal and shell, they are often used instead of or in conjunction with bold font faces.

  3. Color numbers 16 to 231 are RGB colors. These 216 colors are defined by 6 values on each of the three RGB axes. That is, instead of values 0 - 255, each color only ranges from 0 - 5.

    The color number is then calculated like this:

    number = 16 + 36 * r + 6 * g + b
    

    with r, g and b in the range 0 - 5.

  4. The color numbers 232 to 255 are grayscale with 24 shades of gray from dark to light.

  5. The default colors for foreground and background. In many terminals they can be configured independently from the 256 indexed colors, giving an additional two configurable colors . You get them when not setting any other color or disabling other colors (i.e. print '\e[m').

Some sources:

  • urxvt manpage:

    In addition to the default foreground and background colours, urxvt can display up to 88/256 colours: 8 ANSI colours plus high-intensity (potentially bold/blink) versions of the same, and 72 (or 240 in 256 colour mode) colours arranged in an 4x4x4 (or 6x6x6) colour RGB cube plus a 8 (24) colour greyscale ramp.

  • xterm manpage:

    These specify the colors for the 256-color extension. The default resource values are for colors 16 through 231 to make a 6x6x6 color cube, and colors 232 through 255 to make a grayscale ramp.

  • Wikipedia article on ANSI escape codes (which in turn itself is lacking a citation on the topic)


Default RGB values

Theoretically, in order to get an equally distributed range of colors, the RGB values for the colors in the range 16 - 231 could be calculated like this:

# example in Python: // is integer divison, % is modulo
rgb_R = ((number - 16) // 36) * 51
rgb_G = (((number - 16) % 36) // 6) * 51
rgb_B = ((number - 16) % 6) * 51

But it seems that the actual method is different:

Any terminal emulators I tested seems to follow XTerm and map the values [0, 1, 2, 3, 4, 5] for red, green and blue to the values [0, 95, 135, 175, 215, 255] on the RGB color axes. (I tested with XTerm (297) URxvt (v9.19), ROXTerm (2.8.1), gnome-terminal (3.6.2) and xfce4-terminal (0.6.3))

The RGB values for a given index can be calculated with this algorithm:

# example in Python: 'a = b if c else d' is 'a = (c) ? b : d` in C, Perl, etc.
index_R = ((number - 16) // 36)
rgb_R = 55 + index_R * 40 if index_R > 0 else 0
index_G = (((number - 16) % 36) // 6)
rgb_G = 55 + index_G * 40 if index_G > 0 else 0
index_B = ((number - 16) % 6)
rgb_B = 55 + index_B * 40 if index_B > 0 else 0

The grayscale seems to follow this simple formula:

rgb_R = rgb_G = rgb_B = (number - 232) * 10 + 8

256colres.pl in the root of the XTerm sources (version 313) uses a similar algorithm to generate 256colres.h, which contains the color definitions for 256 color mode:

$line1="COLOR_RES(\"%d\",";
$line2="\tscreen.Acolors[%d],";
$line3="\tDFT_COLOR(\"rgb:%2.2x/%2.2x/%2.2x\")),\n";

# colors 16-231 are a 6x6x6 color cube
for ($red = 0; $red < 6; $red++) {
    for ($green = 0; $green < 6; $green++) {
    for ($blue = 0; $blue < 6; $blue++) {
        $code = 16 + ($red * 36) + ($green * 6) + $blue;
        printf($line1, $code);
        printf($line2, $code);
        printf($line3,
           ($red ? ($red * 40 + 55) : 0),
           ($green ? ($green * 40 + 55) : 0),
           ($blue ? ($blue * 40 + 55) : 0));
    }
    }
}

# colors 232-255 are a grayscale ramp, intentionally leaving out
# black and white
$code=232;
for ($gray = 0; $gray < 24; $gray++) {
    $level = ($gray * 10) + 8;
    $code = 232 + $gray;
    printf($line1, $code);
    printf($line2, $code);
    printf($line3,
       $level, $level, $level);
}

Showing available colors in a terminal

Here is a zsh function that prints all colors on a 256 color terminal (if TERM is set to a 256 color value):

function termcolors () 
{
    print TERM
    print -P "Foreground: >ā–ˆ<"
    print -P "Background: >%Sā–ˆ%s<\n"

    print "      0 1 2 3 4 5 6 7" 
    for b (0 1)
    do
        printf "%d %2d " $b $(( 8 * b ))
        for r (0 1 2 3 4 5 6 7)
        do
            c=$(( 8 * b + r ))
            print -nP "%K{$c}  %k"
        done
        printf " %2d\n" $(( 8 * b + 7 ))
    done

    print

    print RGB
    for r (0 1 2 3 4 5)
    do 
        print "$r $(( 16 + 36 * r )) - $(( 16 + 36 * r + 35 ))\n       0 1 2 3 4 5"
        for g (0 1 2 3 4 5)
        do
            printf "%d %3d " $g $(( 16 + 36 * r + 6 * g ))
            for b (0 1 2 3 4 5)
            do
                c=$(( 16 + 36 * r + 6 * g + b ))
                print -nP "%K{$c}  %k"
            done
            printf " %3d\n" $(( 16 + 36 * r + 6 * g + 5))
        done
        print
    done

    print

    print GRAY
    for g in $(seq 0 23)
    do
        c=$(( 232 + g ))
        printf "%2d %3d " $g $c
        print -P "%K{$c}  %k"
    done
}

Changing RGB values during runtime

In some terminals (at least xterm, gnome-terminal, termite and urxvt) all those colors can be changed during runtime by sending one of the following XTerm Control Sequences:

OSC 4; c ; spec BEL
OSC 4; c ; spec ST

where:

  • OSC is the escape character (\e or \033) followed by ]
  • c is the color number (0 - 255)
  • spec is a color specification (e.g. red, #ff0000, rgb:ff/00/00, rgbi:1/0/0 - what actually works might depend on the terminal)
  • BEL is the bell character (\a or \007)
  • ST is the string terminator \e\\ or \033\\

These control sequences can be sent by simply printing them with echo:

echo -en "\e]4;COLOR;SPEC\a"
echo -en "\e]4;COLOR;SPEC\a"

For example, in order to set color number 5 (usually some shade of magenta) to red, either of these should work:

echo -en "\e]4;5;red\a"
echo -en "\e]4;5;#ff0000\e\\"
echo -en "\033]4;5;rgb:ff/00/00\007"

Those colors can be reset to their (configured) default with one of the control sequences

OSC 104 ; c BEL
OSC 104 ; c ST

So the following loop will reset all colors from 0 to 255 to their configured or default value:

for c in {0..255}; do
  echo -en "\e]104;$c\a"
done

For the default foreground and background colors the control sequences are OSC 10 ; spec BEL and OSC 11 ; spec BEL, respectively. For example:

echo -en "\e]10;red\a"
echo -en "\e]11;green\a"

Those can be reset with OSC 110 BEL and OSC 111 BEL respectively:

echo -en "\e]110\a"
echo -en "\e]111\a"
0
Anthony Bourdain On

Here are my color utilities. The most useful is probably the Hex->True, or RGB->256 converters. A lot of this I put together thanks to y'alls help <3

rgbtohex () {
  # usage) `rgbtohex 17 0 26` ==> 1001A
  # usage) `rgbtohex -h 17 0 26` ==> #1001A
  addleadingzero () { awk '{if(length($0)<2){printf "0";} print $0;}';}
  if [[ ${1} == "-h" ]]; then
    r=${2}; g=${3}; b=${4};h='#';
  else
    r=${1}; g=${2}; b=${3};h='';
  fi
  r=`echo "obase=16; ${r}" | bc | addleadingzero`
  g=`echo "obase=16; ${g}" | bc | addleadingzero`
  b=`echo "obase=16; ${b}" | bc | addleadingzero`
  echo "${h}${r}${g}${b}"
}

rgbto256 () {
  # usage: `rgbto256 0 95, 135` ==> 22
  echo "define trunc(x){auto os;os=scale;scale=0;x/=1;scale=os;return x;};" \
    "16 + 36 * trunc(${1}/51) + 6 * trunc(${2}/51) +" \
    " trunc(${3}/51)" | bc
  # XTerm Color Number = 16 + 36 * R + 6 * G + B | 0 <= R,G,B <= 5
}

hextorgb () {
  # usage) `hexttorgb "11001A" ==> 17 0 26
  # usage) `hexttorgb "#11001A" ==> 17 0 26
  hexinput=`echo ${1} | tr '[:lower:]' '[:upper:]'`  # uppercase-ing
  hexinput=`echo ${hexinput} | tr -d '#'`          # remove Hash if needed
  a=`echo ${hexinput} | cut -c-2`
  b=`echo ${hexinput} | cut -c3-4`
  c=`echo ${hexinput} | cut -c5-6`
  r=`echo "ibase=16; ${a}" | bc`
  g=`echo "ibase=16; ${b}" | bc`
  b=`echo "ibase=16; ${c}" | bc`
  echo ${r} ${g} ${b}
}

trueHexPrint () {
  # Generates Truecolor Escape Sequences from Hex Strings. (remove '\\' to use)
  # -fg     Prints as a foreground color. (default)
  # -bg     Prints as a background color.
  # usage) `trueHexPrint -fg "11001A" ==> '\e[38;2;17;0;26m'
  # usage) `trueHexPrint -bg "11001A" ==> '\e[48;2;17;0;26m'
  if [[ ${1} =~ "-fg" || ${1} =~ "-f" ]]; then
    fgbg=38; hexinput=${2};
  elif [[ ${1} =~ "-bg" || ${1} =~ "-b" ]]; then
    fgbg=48; hexinput=${2};
  else
    fgbg=38; hexinput=${1}
  fi
  hexinput=`echo ${hexinput} | tr '[:lower:]' '[:upper:]'`  # uppercase-ing
  hexinput=`echo ${hexinput} | tr -d '#'`               # remove Hash if needed
  a=`echo ${hexinput} | cut -c-2`
  b=`echo ${hexinput} | cut -c3-4`
  c=`echo ${hexinput} | cut -c5-6`
  r=`echo "ibase=16; ${a}" | bc`
  g=`echo "ibase=16; ${b}" | bc`
  b=`echo "ibase=16; ${c}" | bc`
  printf "\\\\e[${fgbg};2;${r};${g};${b}m" # Remove one set of '\\' to utilize
}

XColorTable () {
  i=16
  for ((r = 0; r <= 255; r+=40)); do # Do Tricolor
    for ((g = 0; g <= 255; g+=40)); do
      for ((b = 0; b <= 255; b+=40)); do
    echo "Color$((i++)) = (${r}, ${g}, ${b})"
        if ((b == 0)); then b=55; fi
      done
      if ((b == 0)); then g=55; fi
    done
    if ((r == 0)); then r=55; fi
  done
  for ((m = 8; m <= 238; m+=10)); do # Do Monochrome
    echo "Color$((i++)) = (${m}, ${m}, ${m})"
  done
}

#vim: ft=sh