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

2

31

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

Undercharge answered 26/11, 2014 at 21:37 Comment(4)
Default terminal colors are terminal specific. There are general schemes but I don't think that's a "spec" or anything. And if you have an image like in that second link you can get the RGB values for the colors they used from that easily enough.Frigging
Btw, you can use the Digital Color Meter in the Applications/Utilities folder on OSX to sample colors in any app - including Terminal.Creel
Thanks for the info but I already know how to sample the colors to get the RGB. I was more concerned if there was some specific standard values. See I searched for a standard but did not find one. I didn't want assume that if I couldn't find one then one must not exist. So that is why I was asking. In other words I wasn't sure if the ones in the chart I linked or the ones in my terminal were 'official' or if they were just ones that the developer decided to use.Undercharge
I know this is gonna sound weird, but I gave this an up-vote because... in investigating an answer, I stumbled across Windows WSL stuff, which I would otherwise have remained ignorant of an which turns out to be important. WSL? Try this: learn.microsoft.com/en-us/windows/wsl/installCicatrize
P
63

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"
Premeditation answered 27/11, 2014 at 7:22 Comment(7)
very good! but can you include a source for your initial 4 point definition? (I'd like to read more).Castrate
A very informative, well-researched and presented answer. Nice work!Creel
@Castrate Most of the information in the first section is just accumulated knowledge, so I can not really point to a source for it. I tried to look it up and it is surprisingly difficult to find a good source for this information (or my Google-foo is just not good enough). I added a few bits I found, but to be honest I am not really sattisfied with the results myself.Premeditation
Good info, thanks. I am thinking that maybe there is no real standard but I'm still going to keep searching for a bit.Undercharge
The latest edit talks about 258 colors without clarifying that, and the overall discussion is lacking any sense of when the features were adopted, and why. I don't find it useful.Chiou
@ThomasDickey I agree that saying there being 258 colors may have been confusing; I tried to address that. But I am unsure what you mean by the second part of your comment. By "features" do you mean configurability of foreground and background, or all colors in general? Why would it be useful (not just interesting) to know when this was adopted? Especially when it is nothing recent and seems to have been generally available for years, if not decades. I am sorry, you do not find it useful. But I have to ask: do you mean for answering the question or just for what you have been looking for?Premeditation
swoon I'm not sure whether @ThomasDickey would find this answer useful - I thought I recognised the moniker and there is a very good reason to listen to him when discussing xterm... 8-)Sparrow
E
6

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
Eudiometer answered 9/3, 2019 at 3:33 Comment(3)
if (( b== 0)); then g=55; fi in XColorTable() ( line 10 ) should be if (( g==0 )); then g=55; fiMyalgia
I've modified the XColorTable a little bit to using hex=$(rgbtohex ${r} ${g} ${b}); printf "%-3s = %-18s => %b\n" "$((i++))" "rgb(${r}, ${g}, ${b})" "$(trueHexPrint "${hex}")#${hex}\e[0m" instead of echo "Color$((i++)) = (${r}, ${g}, ${b})", ( same with another echo ), it will print hex and show the colors intuitively ( screenshot )Myalgia
btw I've enhanced the XColorTable to show specific color code, details: gist.github.com/marslo/…. $ xColorTable without parameters will show all 256 colors table; $ xColorTable 30 40 50 will show only color30, color40, and color50 tableMyalgia

© 2022 - 2024 — McMap. All rights reserved.