ターミナル色見本帳

ターミナルに出力する文字に、エスケープシーケンスを用いて色を付けられることはよく知られています。色見本帳のように、具体的な色とエスケースシーケンスのコード値との対応が視覚的にわかりやすい [color-samples](https://github.com/jmatsuzawa/color-samples) というツールを作成しました。

百聞は一見に如かずなので、`color-samples` の実行例を以下に示します。Appleシリコン macOS 15.2のiTerm2 (Build 3.5.10) で実行しています。

![ツール実行例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31469/c1abc08e-bbec-f54d-d0f2-3fc91ef5c7b3.png)

エスケープシーケンスのコード値のテキストを、そのコードで修飾した色で表示しています。ツールはBashで実装していますが、コード値のリテラルはPythonやRuby, Go等多くのプログラミング言語でもそのまま使用可能です。

縦に長く出力されるので `less`に渡したい場合は、`./color-samples | less -R` と `-R` オプションをつけて`less`に色を反映させることができます。
## 補足
    
実際の描画は、お使いの端末 (ターミナルソフト) およびその設定に依存します。端末によっては、RGB指定の24-bitカラーが表示されなかったりします (手元のmacOS標準のTerminal.appのデフォルト設定では24-bitカラーが表示できませんでした)。

エスケープシーケンスの各コード値の意味や詳細については、各所で説明がなされているので、ここでは簡単な補足に留めます。情報を探される場合は、Wikipediaの [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code#Select_Graphic_Rendition_parameters) が体系的にまとめられており、一次資料へのリンクが充実しているだけでなく主要なターミナルソフトの比較や独自拡張にも言及されているので、お勧めです。

### 基本8色

![basic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31469/d3a58bec-fdc4-1c2b-9025-018f4799195c.png)

原色的な基本8色を用いた色見本です。前景色、背景色に各色の組み合わせを表示しています。 `3n` で前景色、`4n` で背景色を指定します。`n` の値により色が変わります。数字一桁の属性値 (例では、`0`, `1`, `2`) は、文字スタイルを指定します。`0` はデフォルトスタイル、`1` は高明度色 (and/or 太字)、`2` は低明度色 (and/or 細字) になります。他の文字スタイルとしてイタリック体や点滅、下線、打消し線等も指定できますが、色と関係ないので、ツール末尾の "[Other styles]" セクションにまとめています。

セクション前半はデフォルト色、後半は高明度色の組み合わせとなっています。

### 拡張 8-bitカラー (256カラー)

![8-bitカラー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31469/421a48f3-67d7-f6e9-34c7-33c6d7269835.png)!

`38;5;n`というコードで拡張前景色、 `48;5;n` で拡張背景色を指定できます。`n` の値によって色が変わります。

`0 <= n <= 15` の範囲は、基本8色セクションで示したデフォルト色8種および高明度色8種と同じなので、ツールでは割愛しています。

`16 <= n <= 231` の範囲は、6 x 6 x 6の216色になります。`n = 6^2 * r + 6^1 * g + 6^0 * b + 16 [0 <= r, g, b <= 5]` です。ツールでは、6 x 6 x 6のブロックで表示しています。

`232 <= n <= 255` の範囲はグレースケールになります。

8-bitカラーは、色の種類が多くなるので背景色と、前景色を分けて色見本を作成しています。前景色、背景色を組み合わせたい場合は、`\033[38;5;n;48;5;nm`のように連結すれば可能です。

![combination.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31469/8f508309-3993-c770-0110-eded7aeab539.png)

### RGB 24-bitカラー

![24-bitカラー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31469/22f85dd7-4ef7-edb7-113c-2a94165b82f1.png)

`38;2;r;g;bm` というコードで前景色、`48;2;r;g;bm`で背景色を指定できます。`r`, `g`, `b` はそれぞれ 0..255の範囲で指定できます。ツールでは色見本として視覚的に効果が分かりやすいグラデーションとなる値をピックアップしています。

より細かな色指定が可能になるので、端末を伝統色で雅に飾ることもできます。
![伝統色](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31469/1ad70383-758d-5ec0-9086-eabec58242a2.png)

画面制御のエスケープシーケンスと組み合わせて、添付動画のような虹色に輝くテキストを表現することもシェルで可能です。実用性はありません (インタラクティブなCLIゲームやジョークツールで視覚効果を狙うことくらいならできるかもしれません)。

![虹色テキスト](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31469/f3183105-f10d-8bee-3e02-6ff67f6a355d.gif)

<details>
<summary>実装コード</summary>

```sh
#!/usr/bin/env bash

# foreground colors
fc=(
  '38;2;0;203;203'
  '38;2;0;152;203'
  '38;2;0;100;203'
  '38;2;0;50;203'
  '38;2;0;0;203'
  '38;2;50;0;203'
  '38;2;100;0;203'
  '38;2;152;0;203'
  '38;2;203;0;203'
  '38;2;203;0;152'
  '38;2;203;0;100'
  '38;2;203;0;50'
  '38;2;203;0;0'
  '38;2;203;50;0'
  '38;2;203;100;0'
  '38;2;203;152;0'
  '38;2;203;203;0'
  '38;2;152;203;0'
  '38;2;100;203;0'
  '38;2;50;203;0'
  '38;2;0;203;0'
  '38;2;0;203;50'
  '38;2;0;203;100'
  '38;2;0;203;152'
)

# background colors
bc=(
  '48;2;255;153;153'
  '48;2;255;178;153'
  '48;2;255;204;153'
  '48;2;255;229;153'
  '48;2;255;255;153'
  '48;2;229;255;153'
  '48;2;204;255;153'
  '48;2;178;255;153'
  '48;2;153;255;153'
  '48;2;153;255;178'
  '48;2;153;255;204'
  '48;2;153;255;229'
  '48;2;153;255;255'
  '48;2;153;229;255'
  '48;2;153;204;255'
  '48;2;153;178;255'
  '48;2;153;153;255'
  '48;2;178;153;255'
  '48;2;204;153;255'
  '48;2;229;153;255'
  '48;2;255;153;255'
  '48;2;255;153;229'
  '48;2;255;153;204'
  '48;2;255;153;178'
)

# スクリプト終了時に文字属性をクリア
trap 'printf "\033[m" && exit' 0 1 2 3 15

printf '\033[2J' # 画面クリア
i=0
while :; do
  printf '\033[H' # カーソルを原点へ移動 (下のprintfと1行にまとめてもよい)
  printf "\033[1;${fc[i]};${bc[i]}m%s\033[m\n" 'hello world'
  sleep 0.1
  i=$(( (i+1) % ${#bc[@]} ))
done
```
</details>