2017/06/19

端末の256色と24bitカラー(1677万色)の対応と設定・色指定

端末の256色と24bitカラー(16,777,216色)の対応状況とこれらに関する設定、色変更の指定形式についてを扱う。

元の記事は2008年7月に256色拡張に関するものとして書かれたが、24bitカラーなどについての内容を追加して全体を書き直している。

  1. 対応状況と設定
    1. VTE系
    2. Konsole
    3. rxvt-unicode
    4. mlterm
    5. tmux
  2. 色対応の動作テスト
    1. 256色
    2. 24bitカラー
  3. 色の指定
    1. 色指定に関係するエスケープシーケンス
    2. 256色の色番号とパレット
      1. xtermの既定のパレット

対応状況と設定

VTE系

GTK+アプリケーション内で使用可能な “端末” のGUI部品を提供するライブラリである “VTE” を用いた端末アプリケーションについては、GTK+ 3に対応しているバージョン2.9x系のものは256色と24bitカラーの両方に対応しているが、GTK+ 2用の古いバージョン系列のものは256色にしか対応していない。

GTK+を用いたデスクトップ環境に付属している端末アプリケーションは基本的にVTEを用いており、GTK+ 3対応のデスクトップ環境に付属しているものは24bitカラーに対応している。そうでないものについても、その端末アプリケーションがGTK+ 3を用いていれば24bitカラーが使用できる。

Konsole

バージョン16.12.3時点では256色と24bitカラーの両方に対応している。

rxvt-unicode

256色対応についてはconfigure--enable-256-colorオプションを付けてビルドすればよい。

24bitカラーについてはバージョン9.22時点では未対応だが、別の作者による24bitカラー対応済みの改変版が非公式なリポジトリで公開されているため、このソースツリーを用いてconfigure--enable-24-bit-colorオプションを付けてビルドすればよい。

256色と24bitカラーの対応を有効にしたUbuntu向けパッケージをppa:kakurasan/miscで公開している。

mlterm

256色は標準で対応しているが、24bitカラーはバージョン3.5.0時点では部分的な対応にとどまる(限られた色数の中の近い色で表示される、不完全な形のサポート)。

tmux

tmux内の24bitカラー表示についてはバージョン2.2以上で対応しており、これを動かす端末側が24bitカラーに対応していれば以下の記述の追加で対応できる。

[追記]ファイル名:[ホームディレクトリ]/.tmux.conf
set-option -ga terminal-overrides ",xterm-256color:Tc"
set -g default-terminal "xterm-256color"

カスタムセッションの記述を同ファイルで行っている場合、上記の指定は先に(設定ファイルの先頭に近い場所へ)記述しておく。

設定ファイルの “status-” 系の指定などで色を記述する際には “#” に続く6桁の16進表記(例:“#ffffff”)が使用できる。ただし、 “#” はコメント記号でもあるので、色指定を含む値は全体をダブルクォートで囲む必要がある。

[一部]ファイル名:[ホームディレクトリ]/.tmux.conf
set-window-option -g mode-fg "#ffafd7"
set-option -g status-right "#[fg=#5fd7af,bold]#T#[default]"

256色までにしか対応していない環境で動かす場合は256色の色番号を用いる記法(“colour[色番号]”)を使う方法もある。

色対応の動作テスト

256色

(256色拡張の色を順に並べて表示)
bash/zsh$ for i in $(seq 16 255); do printf "\e[48;5;${i}m \e[0m"; done; echo

実行結果:

256色テスト

dashなどのシェルでは組み込みコマンドのprintfechoの関係で色の切り替えがうまく動かないことがある(同名の外部コマンドを使うと動作する)。本記事内の後述の実行例でも同様。

256色のテスト用スクリプトとしては256colors2.plなどが有名。

seqコマンドについては以下を参照。

24bitカラー

(黒から白のグラデーションを表示)
bash/zsh$ for i in $(seq 0 255); do printf
 "\e[48;2;${i};${i};${i}m \e[0m"; done; echo

(黒から赤のグラデーションを表示)
bash/zsh$ for i in $(seq 0 255); do printf
 "\e[48;2;${i};0;0m \e[0m"; done; echo

(黒から緑のグラデーションを表示)
bash/zsh$ for i in $(seq 0 255); do printf
 "\e[48;2;0;${i};0m \e[0m"; done; echo

(黒から青のグラデーションを表示)
bash/zsh$ for i in $(seq 0 255); do printf
 "\e[48;2;0;0;${i}m \e[0m"; done; echo

実行結果:

24bitカラーテスト

これ以外には、24bitカラー対応についてまとめられた英語のページのはじめのあたりに幾つかの実行例コードがある他、外部のサンプルスクリプトへのリンクもある。

色の指定

色指定に関係するエスケープシーケンス

赤・緑・青の各成分の指定については “10” と付けたものが10進表記(0から255)、 “16” と付けたものが16進表記(00からff)となる。

項目記述
文字色を変更(256色)\e[38;5;[色番号]m
文字色を変更(24bitカラー色)\e[38;2;[赤10];[緑10];[青10]m
背景色を変更(256色)\e[48;5;[色番号]m
背景色を変更(24bitカラー色)\e[48;2;[赤10];[緑10];[青10]m
256色拡張の色番号に色を割り当てる\e]4;[色番号];rgb:[赤16]/[緑16]/[青16]\a もしくは \e]4;[色番号];#[赤16][緑16][青16]\a
文字色を戻す\e[39m
背景色を戻す\e[49m
全指定を戻す\e[0m

256色の色番号とパレット

256色拡張で用いられる色番号の範囲は16〜255番となっている。

元々xtermには既定のパレット割り当て(番号と色の対応)が存在しており、他の端末アプリケーションでもこれと同じ割り当てがされているため、256色対応とされている端末ソフトウェアではこの対応により番号から実際の表示色が決められる。

一方で、256色対応の端末ソフトウェアにおいては24bitカラーの1677万色の中から240色を自由に割り当てることができる仕組みになっている。

例として、17番の色を#feccf0にしたい場合は下のようにする。このコマンド実行によって文字は出力されない。

(赤・緑・青それぞれの値を分けて指定する形)
bash/zsh$ printf "\e]4;17;rgb:fe/cc/f0\a"

(6桁の16進表記を用いて指定する形)
bash/zsh$ printf "\e]4;17;#feccf0\a"

256colors2.plの前半にはこの割り当て処理が入っているため、色の割り当てをカスタマイズしている場合に実行すると中身がxtermの既定のパレットと同じ内容に書き換えられてしまう。

xtermの既定のパレット

16〜231番は赤・緑・青それぞれの成分が0x00,0x5f,0x87,0xaf,0xd7,0xffの6段階となる63=216種類の組み合わせで構成され、途中の値の間隔は均等ではない(0x330x66などにはなっていない)。

232〜255番は全て無彩色(赤・緑・青の成分が全て同一値)で、かつ16〜231番の範囲に含まれない(無彩)色を細かく並べたものとなる。具体的には赤・緑・青の成分値が0x08,0x12,0x1c,0x26,0x30,0x3a,0x44,0x4e,0x58,0x62,0x6c,0x76,0x80,0x8a,0x94,0x9e,0xa8,0xb2,0xbc,0xc6,0xd0,0xda,0xe4,0xeeの24色となる。

具体的な色番号と表示色(6桁16進表記)との対応は下のスクリプトの出力で一覧できる。

[任意]ファイル名:gen-256color-default-palette.py ライセンス:CC0
#! /usr/bin/python

# CC0

from __future__ import print_function


# 16 -> 231
red = 0
while red < 6:
  green = 0
  while green < 6:
    blue = 0
    while blue < 6:
      print ('{0:3d}:#{1:02x}{2:02x}{3:02x}'.format (16 + (red * 36) + (green * 6) + (blue * 1),
                                                     (red * 40 + 55) if red > 0 else 0,
                                                     (green * 40 + 55) if green > 0 else 0,
                                                     (blue * 40 + 55) if blue > 0 else 0))
      blue += 1
    green += 1
  red += 1

# 232 -> 255
gray = 0
while gray < 24:
  level = gray * 10 + 8
  print ('{0:3d}:#{1:02x}{2:02x}{3:02x}'.format (232 + gray, level, level, level))
  gray += 1

下のスクリプトはHTML形式で一覧表を生成する。これを実行して出力をファイルにリダイレクトして保存後にWebブラウザで開くと色一覧が確認でき、表の各セル内を選択すると色番号と表示色が見られる。24bitカラーで細かい色を指定する際にも、大まかな色を決めるのに役立つかもしれない。

xtermの既定の256色パレットをHTMLに出力したもの

[任意]ファイル名:gen-256color-default-palette-html.py ライセンス:CC0
#! /usr/bin/python

# CC0

from __future__ import print_function


def print_html (html):
  print (html, end = '');


print_html ('<!DOCTYPE html>')
print_html ('<html><head><title>xterm default 256color palette</title></head><body>')

# 16 -> 231
red = 0
while red < 6:
  green = 0
  print_html ('<table style="width:100%"><thead><tr><th>&nbsp;</th>')
  for i in range (6):
    print_html ('<th style="width:4%">{0}</th>'.format (i))
  print_html ('</tr></thead><tbody>')
  while green < 6:
    blue = 0
    print_html ('<tr><th>{0}</th>'.format (16 + (red * 36) + (green * 6) + (blue * 1)))
    while blue < 6:
      color = '#{0:02x}{1:02x}{2:02x}'.format ((red * 40 + 55) if red > 0 else 0,
                                               (green * 40 + 55) if green > 0 else 0,
                                               (blue * 40 + 55) if blue > 0 else 0)
      print_html ('<td style="color:{1}; background:{1}; width:16%">{0}:{1}</td>'.format (16 + (red * 36) + (green * 6) + (blue * 1), color))
      blue += 1
    print_html ('</tr>')
    green += 1
  print_html ('</tbody></table>')
  red += 1

# 232 -> 255
gray = 0
print_html ('<table style="width:100%"><thead><tr><th>&nbsp;</th>')
for i in range (6):
  print_html ('<th style="width:4%">{0}</th>'.format (i))
print_html ('</tr></thead><tbody>')
while gray < 4:
  gray2 = 0
  print_html ('<tr><th>{0}</th>'.format (gray * 6 + 232))
  while gray2 < 6:
    level = gray * 60 + gray2 * 10 + 8
    color = '#{0:02x}{1:02x}{2:02x}'.format (level, level, level)
    print_html ('<td style="color:{1}; background:{1}; width:16%">{0}:{1}</td>'.format (232 + gray * 6 + gray2, color))
    gray2 += 1
  print_html ('</tr>')
  gray += 1

print_html ('</tbody></table></body></html>')
使用したバージョン:
  • VTE 0.44.2(2.91), 0.28.2
  • Konsole 16.12.3
  • rxvt-unicode 9.22
  • mlterm 3.5.0
  • tmux 2.3
  • bash 4.4
  • zsh 5.2
  • dash 0.5.8
  • Python 2.7.13, 3.5.3