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

爱⌒轻易说出口 提交于 2019-12-02 16:48:15
Adaephon

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"

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!