Ansi扩展颜色索引(17-255)中颜色的RGB值

28

我的问题是关于使用 ANSI 颜色的 shell 脚本,但参考操作系统为 Apple Mac OS X 10.9 Mavericks。我将 "iTerm" 终端应用程序设置为默认终端,但也检查了内置的 "terminal" 应用程序。我使用 ZSH (5.0.7) 作为默认 shell,但也在 BASH (3.2.51) 中进行了检查。

我一直在尝试找出是否有一份可用于使用 esc[38;5;xm 和 esc[48;5;xm 的 256 色索引扩展前/背景 Ansi 转义代码的 RGB 值列表,其中 x 是从 0 到 255 的数字。我找到了一些脚本可以打印颜色块(使用索引),但我想知道每个色彩索引中每种颜色的 RGB 值。

这里是使用 ansi 代码的示例:

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

(\e可以被替换为\033或\x1b)

基本上我想知道是否有一个针对这些索引颜色的列表或约定的设置?例如232-255似乎总是一种灰度渐变。我找到的每个涉及扩展颜色的站点基本上只说如何使用它,没有列出任何特定的颜色。

我找到了一些关于X11和一个rgb.txt文件的参考资料,起初看起来像是我要找的东西,但它们似乎不匹配索引号。我在找到的文件中有752种颜色(大多数都是重复的,假设有376种,这仍然超过256)。还有50种灰色(如果计算重复,则为100种),但Ansi索引颜色只有23种,所以似乎不是同一种颜色。如果它们以某种方式包含了ansi扩展颜色索引中的颜色,那么有没有哪个名称在哪个索引中的列表?

PS. 我知道esc[38;2;r;g:bm据说可以使用rgb值设置颜色,但我无法在我的Mac上使其工作,而且我更感兴趣的是索引颜色的默认值。

一些网站:(由于低声望,只能发布2个?但我检查了很多站点)

这个网站有标准颜色的rgb,但没有扩展颜色。

这个网站有一个颜色表,但没有rgb值。


默认终端颜色是特定于终端的。虽然有一些通用方案,但我不认为那是一个“规范”或任何东西。如果您有像第二个链接中那样的图像,您可以轻松地从中获取所使用颜色的RGB值。 - Etan Reisner
顺便提一下,您可以在OSX的Applications/Utilities文件夹中使用“数字颜色计”来采样任何应用程序中的颜色,包括终端。 - Mark Setchell
谢谢提供信息,但我已经知道如何取样颜色以获取RGB值。我更关心的是是否有一些特定的标准值。我搜索了标准,但没有找到。我不想假设如果我找不到一个标准,那么就不存在这样的标准。这就是为什么我在问的原因。换句话说,我不确定链接图表中的值或终端中的值是否是“官方”的,还是开发人员决定使用的值。 - Jim Knecht
我知道这听起来有点奇怪,但我给了这个答案一个赞,因为...在调查一个答案时,我偶然发现了Windows WSL相关的东西,否则我将一无所知,而这些东西事实证明是很重要的。WSL?试试这个链接:https://learn.microsoft.com/en-us/windows/wsl/install - Richard T
2个回答

60

256色表及其分区

256色终端的颜色范围由4个部分组成,通常是5个部分,这种情况下实际上会得到258种颜色:

  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').

一些来源:

  • urxvt 手册:

    除了默认的前景色和背景色,urxvt可以显示最多88/256种颜色:8个ANSI颜色加上相同颜色的高强度(可能是粗体/闪烁),以及72(或240在256色模式下)种颜色排列成一个4x4x4(或6x6x6)颜色RGB立方体和一个8(24)颜色灰度坡道。

  • xterm 手册:

    这些指定256色扩展的颜色。默认资源值为颜色16到231,形成6x6x6色彩立方体,颜色232到255形成灰度坡道。

  • Wikipedia关于ANSI转义代码的文章(本身也缺少有关该主题的引用)


默认RGB值

理论上,为了获得均匀分布的颜色范围,可以按照如下计算方法获取范围16-231内颜色的RGB值:

# 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

但是事实上,实际方法似乎是不同的:

我测试过的任何终端仿真器似乎都遵循XTerm并将红色、绿色和蓝色的值[0, 1, 2, 3, 4, 5]映射到RGB颜色轴上的值[0, 95, 135, 175, 215, 255]。(我测试了XTerm(297)URxvt(v9.19),ROXTerm(2.8.1),gnome-terminal(3.6.2)和xfce4-terminal(0.6.3))

给定索引的RGB值可以使用以下算法计算:

# 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

灰度似乎遵循这个简单的公式:
rgb_R = rgb_G = rgb_B = (number - 232) * 10 + 8

256colres.pl位于XTerm源代码(版本313)的根目录中,使用类似的算法生成256colres.h,其中包含256色模式的颜色定义:

$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);
}

在终端中显示可用颜色

这是一个zsh函数,可以在256色终端上打印所有颜色(如果TERM设置为256色值):

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
}

运行时更改RGB值

在某些终端(至少包括xtermgnome-terminaltermiteurxvt),可以通过发送以下XTerm控制序列之一来更改所有这些颜色:

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

其中:

  • OSC 是转义字符 (\e\033) 后跟随 ]
  • c 是颜色编号 (0 - 255)
  • spec 是颜色规范 (例如 red, #ff0000, rgb:ff/00/00, rgbi:1/0/0 - 实际可行性可能取决于终端)
  • BEL 是响铃字符 (\a\007)
  • ST 是字符串终止符 \e\\\033\\

可以通过简单地使用 echo 命令来发送这些控制序列:

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

例如,为了将颜色编号5(通常是品红色调)设置为红色,以下任意一种方法都可以:
echo -en "\e]4;5;red\a"
echo -en "\e]4;5;#ff0000\e\\"
echo -en "\033]4;5;rgb:ff/00/00\007"

这些颜色可以通过其中一个控制序列重置为它们的(配置的)默认值。
OSC 104 ; c BEL
OSC 104 ; c ST

因此,以下循环将重置所有颜色从0到255的配置或默认值:

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

默认的前景色和背景色的控制序列分别为OSC 10 ; spec BELOSC 11 ; spec BEL。例如:
echo -en "\e]10;red\a"
echo -en "\e]11;green\a"

这些可以通过分别使用 OSC 110 BELOSC 111 BEL 来重置:
echo -en "\e]110\a"
echo -en "\e]111\a"

1
非常好!但是你能否提供一下你最初的四点定义的来源?(我想多了解一些)。 - shellter
一個非常有信息量、經過深入研究和呈現的答案。做得好! - Mark Setchell
最新的编辑提到了258种颜色,但没有澄清具体情况,而且整个讨论缺乏关于这些功能何时以及为什么被采用的任何意义。我觉得这并不有用。 - Thomas Dickey
@ThomasDickey 我同意说有258种颜色可能会让人感到困惑;我试图解决这个问题。但是我不确定你在评论的第二部分中所指的是什么。通过“特性”,您是指前景和背景的可配置性,还是所有颜色的一般性?为什么知道这一点会很有用(而不仅仅是有趣)?特别是当它并不是最近的事情,并且似乎已经普遍存在了数十年,甚至更长时间。很抱歉,您觉得这没有用。但我必须问一下:您是指回答问题还是只是为了您一直在寻找的东西? - Adaephon
我不确定@ThomasDickey是否会发现这个答案有用 - 我认为我认出了这个名字,而且在讨论“xterm”时听他的话有一个非常好的理由... 8-) - SlySven
显示剩余2条评论

4
这里是我的颜色工具。其中最有用的可能是转换十六进制到真彩或者 RGB 到 256 的转换器。这些工具的制作很大程度上得益于你们的帮助 <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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接