初歩のシェルスクリプトで遊ぶ[端末の256色カラーセレクタ(1)]

寄せ集めででっち上げた256色サンプル画像作成スクリプト





端末用の256色のサンプル画像。
色の一覧から、文字色と背景色を拾うスクリプトを作っとるんすが、そのスクリプト用のシェル関数を組み合わせた、サンプル画像作成スクリプトです。
なんだかんだで、使うのって、手間かけたものより、画像一枚だったりするんすよね。

カラーセレクタスクリプト自体はだいたい出来てるんだけれど、まだ迷ってるところもあるんで、まずはこれから。
以下のスクリプト自体は、ただの色サンプルに余計なことをやりすぎ、ではあるんだけれど。

ひとつだけ機能

このスクリプトに付加した機能が一つだけ。
色番号の数字は、黒か、白かを自動で切り替えてます。この閾値の指定です。
RGBの値から明るさを出すのに、「Y=0.3R+0.59G+0.11B」で計算してます。このYのどこで、黒数字と白数字を切り分けるかの指定が可能です。
つまり、文字を白にするなら、背景色はこの色にするとコントラストを確保できますよと。そういう判断の参考にできる。

#!/bin/sh
#!/bin/dash
#!/bin/busybox sh
#!/usr/bin/posh
#!/usr/bin/yash
#!/bin/bash
#!/usr/bin/ksh
#!/usr/bin/zsh

# ========================================================================================
# ■ 端末256色 色と番号の一覧画像作成 v1.0
# https://twitter.com/beta_reverse_2
# ========================================================================================
# 
# カラーリスト表の何番を表示するのか
colorTableNo=${1:-0}

# 表示幅は何文字分か
imageWidth=${2:-120}

# 色番号の数字は、黒い文字と白い文字、どちらで表示するのか
# 明るさ[0-255]の間で、どこを境目に白文字と黒文字を切り替えるのか
fontThreshold=${3:-127}


# PATH="./lib:${PATH}" # ====[shMerge<disable>]==== #_shMergeDisabled



# # ====[shMerge]====	colorTableListSh	20201017_191014
colorTableListSh(){ (	# ====[shMerge<ins>]====
#!/bin/sh
# 引数に数字を与えると、その番号のカラーパレットデータを出力する
# パレットデータの数字は「0-255」
# 行のデータはタブ区切りにする
# 1行に入れる数値データの数は、360の約数にする
# 行数に制限は無いが、端末表示に収まる行数に。
# 「0-255」を、すべて必ず1回ずつ使わなければならない。
# 同じ数字を複数回使ってはいけない。
# カスタマイズするなら、既存のカラーパレットをベースにして、行単位で入れ替えると簡単。

# カラーパレット_色相HSL 色の濃さ => 明るさ => 色合い
Palette0='0	1	2	3	4	5	6	7
8	9	10	11	12	13	14	15
232	233	234	235	236	237	238	239	240	241	242	243
244	245	246	247	248	249	250	251	252	253	254	255
16	59	102	145	188	231
95	101	65	66	60	96
138	144	108	109	103	139
131	137	143	107	71	72	73	67	61	97	133	132
181	187	151	152	146	182
174	180	186	150	114	115	116	110	104	140	176	175
167	173	179	185	149	113	77	78	79	80	74	68	62	98	134	170	169	168
52	58	22	23	17	53
88	94	100	64	28	29	30	24	18	54	90	89
124	130	136	142	106	70	34	35	36	37	31	25	19	55	91	127	126	125
160	166	172	178	184	148	112	76	40	41	42	43	44	38	32	26	20	56	92	128	164	163	162	161
196	202	208	214	220	226	190	154	118	82	46	47	48	49	50	51	45	39	33	27	21	57	93	129	165	201	200	199	198	197
203	209	215	221	227	191	155	119	83	84	85	86	87	81	75	69	63	99	135	171	207	206	205	204
210	216	222	228	192	156	120	121	122	123	117	111	105	141	177	213	212	211
217	223	229	193	157	158	159	153	147	183	219	218
224	230	194	195	189	225'


# HSV S=>V=>H
Palette1='0	1	2	3	4	5	6	7
8	9	10	11	12	13	14	15
232	233	234	235	236	237	238	239	240	241	242	243
244	245	246	247	248	249	250	251	252	253	254	255
16	59	102	145	188	231
224	230	194	195	189	225
181	187	151	152	146	182
138	144	108	109	103	139
95	101	65	66	60	96
217	223	229	193	157	158	159	153	147	183	219	218
174	180	186	150	114	115	116	110	104	140	176	175
131	137	143	107	71	72	73	67	61	97	133	132
210	216	222	228	192	156	120	121	122	123	117	111	105	141	177	213	212	211
167	173	179	185	149	113	77	78	79	80	74	68	62	98	134	170	169	168
203	209	215	221	227	191	155	119	83	84	85	86	87	81	75	69	63	99	135	171	207	206	205	204
52	58	22	23	17	53
88	94	100	64	28	29	30	24	18	54	90	89
124	130	136	142	106	70	34	35	36	37	31	25	19	55	91	127	126	125
160	166	172	178	184	148	112	76	40	41	42	43	44	38	32	26	20	56	92	128	164	163	162	161
196	202	208	214	220	226	190	154	118	82	46	47	48	49	50	51	45	39	33	27	21	57	93	129	165	201	200	199	198	197'

# カラーパレット_色番号順
Palette2='0	1	2	3	4	5	6	7
8	9	10	11	12	13	14	15
232	233	234	235	236	237	238	239	240	241	242	243
244	245	246	247	248	249	250	251	252	253	254	255
16	17	18	19	20	21	22	23	24	25	26	27	28	29	30	31	32	33
34	35	36	37	38	39	40	41	42	43	44	45	46	47	48	49	50	51
52	53	54	55	56	57	58	59	60	61	62	63	64	65	66	67	68	69
70	71	72	73	74	75	76	77	78	79	80	81	82	83	84	85	86	87
88	89	90	91	92	93	94	95	96	97	98	99	100	101	102	103	104	105
106	107	108	109	110	111	112	113	114	115	116	117	118	119	120	121	122	123
124	125	126	127	128	129	130	131	132	133	134	135	136	137	138	139	140	141
142	143	144	145	146	147	148	149	150	151	152	153	154	155	156	157	158	159
160	161	162	163	164	165	166	167	168	169	170	171	172	173	174	175	176	177
178	179	180	181	182	183	184	185	186	187	188	189	190	191	192	193	194	195
196	197	198	199	200	201	202	203	204	205	206	207	208	209	210	211	212	213
214	215	216	217	218	219	220	221	222	223	224	225	226	227	228	229	230	231'

Palette3='0	1	2	3	4	5	6	7
8	9	10	11	12	13	14	15
232	233	234	235	236	237	238	239	240	241	242	243
244	245	246	247	248	249	250	251	252	253	254	255
16	59	102	145	188	231
52	58	22	23	17	53
88	94	100	64	28	29	30	24	18	54	90	89
124	130	136	142	106	70	34	35	36	37	31	25	19	55	91	127	126	125
160	166	172	178	184	148	112	76	40	41	42	43	44	38	32	26	20	56	92	128	164	163	162	161
95	101	65	66	60	96
196	202	208	214	220	226	190	154	118	82	46	47	48	49	50	51	45	39	33	27	21	57	93	129	165	201	200	199	198	197
131	137	143	107	71	72	73	67	61	97	133	132
138	144	108	109	103	139
167	173	179	185	149	113	77	78	79	80	74	68	62	98	134	170	169	168
174	180	186	150	114	115	116	110	104	140	176	175
203	209	215	221	227	191	155	119	83	84	85	86	87	81	75	69	63	99	135	171	207	206	205	204
181	187	151	152	146	182
210	216	222	228	192	156	120	121	122	123	117	111	105	141	177	213	212	211
217	223	229	193	157	158	159	153	147	183	219	218
224	230	194	195	189	225'

Palette4='0	1	2	3	4	5	6	7
8	9	10	11	12	13	14	15
232	233	234	235	236	237	238	239	240	241	242	243
244	245	246	247	248	249	250	251	252	253	254	255
16	59	102	145	188	231
52	58	22	23	17	53
95	101	65	66	60	96
88	94	100	64	28	29	30	24	18	54	90	89
138	144	108	109	103	139
131	137	143	107	71	72	73	67	61	97	133	132
124	130	136	142	106	70	34	35	36	37	31	25	19	55	91	127	126	125
181	187	151	152	146	182
174	180	186	150	114	115	116	110	104	140	176	175
167	173	179	185	149	113	77	78	79	80	74	68	62	98	134	170	169	168
160	166	172	178	184	148	112	76	40	41	42	43	44	38	32	26	20	56	92	128	164	163	162	161
224	230	194	195	189	225
217	223	229	193	157	158	159	153	147	183	219	218
210	216	222	228	192	156	120	121	122	123	117	111	105	141	177	213	212	211
203	209	215	221	227	191	155	119	83	84	85	86	87	81	75	69	63	99	135	171	207	206	205	204
196	202	208	214	220	226	190	154	118	82	46	47	48	49	50	51	45	39	33	27	21	57	93	129	165	201	200	199	198	197'


# 存在するデータの番号を入力されたとき、そのデータを出力して、exit 0
# 存在しないデータの番号を入力されたとき、exit 1

eval 'XX=`echo "${Palette'${1:-0}'}"`'
if test -n "${XX}" ; then
	eval 'echo "${Palette'${1:-0}'}"'
	exit 0
else
	exit 1
fi
# [EOF]
) }	# ====[shMerge</ins>]====

# # ====[shMerge]====	ansi256matrixToViewCodeSh	20201017_191014
ansi256matrixToViewCodeSh(){ (	# ====[shMerge<ins>]====
#!/bin/sh
# カラーパレット表を読み込んで、パレットを端末表示するためのデータを作成する。
# 表示幅(文字数)は指定できる。
# 一行に指定されるパレットの数が増減しても、表示幅を同じ幅に揃える。
roundSh(){ (
Width=${1:?'横幅指定が必要'}
Part=${2:?'分割数指定が必要'}

# 余った文字数
Remaind=$(( ${Width} % ${Part} ))
# 余った文字を振り分ける行番号リスト
addLines=''

NN=1
while test ${NN} -le ${Remaind} ; do
addLines="${addLines}$(( ( ${Part} * ${NN} ) / ( ${Remaind} + 1 ) + 1 ))
"
NN=$(( ${NN} + 1 ))
done

#echo "${addLines}" # 【debug】

partNo='1'
while test "${partNo}" -le "${Part}" ; do
addLineFlag='false'

# ${partNo}が 指定値と同じなら フラグtrue
while read addLine ; do
  if test -z "${addLine}" ; then
	continue
elif test "${partNo}" -eq "${addLine}" ; then
	addLineFlag='true'
fi
done << ____ADD_LINES
${addLines}
____ADD_LINES

#printf '%d:' "${partNo}" # 【debug】

# trueのとき1加算
if ${addLineFlag} ; then
	echo $(( ${Width} / ${Part} + 1 ))
else
	echo $(( ${Width} / ${Part} ))
fi

partNo=$(( ${partNo} + 1 ))
done

exit 0
) }

# 全体の横幅は何文字にするのか
Cols=${1:-78}

while read LINE ; do

eval set -- ${LINE}

addChars=`roundSh ${Cols} ${#}`

NUM=0
while read NN ; do
	NUM=$(( ${NUM} + 1 ))
	eval 'wordLength_'${NUM}'=${NN}'
done << ____add
${addChars}
____add


NUM=0
for Index in ${@} ; do
NUM=$(( ${NUM} + 1 ))

# wordLength インデックスカラーを表示する幅を文字数で
eval 'wordLength=${wordLength_'${NUM}'}'

# Index        インデックス番号
# wordLength   表示幅を文字数で
echo "${Index}	${wordLength}"

done

echo '0	-1'
done
) }	# ====[shMerge</ins>]====

# # ====[shMerge]====	ansi256_numToRGBsh	20201017_191014
ansi256_numToRGBsh(){ (	# ====[shMerge<ins>]====
#!/bin/sh


# 標準入力から「0-255」の数字を入力すると、
# RGB256階調の数値を出力する。
# 「0-16」のときは「__」を出力する。(「--」「-」は不適切 「set --」関係)


while read Index ; do
RR='__'
GG='__'
BB='__'


if test "${Index}" -ge 0 && test "${Index}" -le 15 ; then

echo "${RR}	${GG}	${BB}	${Index}"

elif test "${Index}" -ge 16 && test "${Index}" -le 231 ; then

numTo256Func(){
# ${1}:代入する変数名 RR,GG,BBのいずれか
# ${2}:「0-5」の数値 RGBのレベル指定
case "${2}" in
( 0 ) eval ${1}'=0' ;;
( 1 ) eval ${1}'=95' ;;
( 2 ) eval ${1}'=135' ;;
( 3 ) eval ${1}'=175' ;;
( 4 ) eval ${1}'=215' ;;
( 5 ) eval ${1}'=255' ;;
esac
}

numTo256Func RR $(( ( ${Index} - 16 ) / 36 ))
numTo256Func GG $(( ( ( ${Index} - 16 ) % 36 ) / 6 ))
numTo256Func BB $(( ( ( ${Index} - 16 ) % 36 ) % 6 ))

echo "${RR}	${GG}	${BB}	${Index}"

elif test "${Index}" -ge 232 && test "${Index}" -le 255 ; then


RR=$(( ( ( ${Index} - 232 ) * 10 ) + 8 ))
GG="${RR}"
BB="${RR}"

echo "${RR}	${GG}	${BB}	${Index}"

fi
done
) }	# ====[shMerge</ins>]====



# 奇数行は1,偶数行は-1
OddEven='1'

colorTableListSh ${colorTableNo} |         # 色番号表を呼び出す
while read tableRow ; do                   # 行を2行ずつ出力する
echo "${tableRow}"
echo "${tableRow}"
done |
ansi256matrixToViewCodeSh ${imageWidth} |  # 一色一色の表示横幅を計算
while read Palette Nums ; do # ----------------------------------------------------↓
# Palette 色番号[0-255]
# Nums    色の表示幅文字数

# Numsが負ならば改行する
if test ${Nums} -le -1 ; then
printf '\033[0m\n'
OddEven=$(( ${OddEven} * -1 ))
continue
fi

# RGBの値を取得 RGBから明るさYを計算
# Y = 0.3R + 0.59G + 0.11B

RGB=`echo "${Palette}" | ansi256_numToRGBsh `
RR=`echo "${RGB}" | cut -f 1`
GG=`echo "${RGB}" | cut -f 2`
BB=`echo "${RGB}" | cut -f 3`

if YY=`expr '(' 30 '*' ${RR} + 59 '*' ${GG} + 11 '*' ${BB} ')' / 100 2>/dev/null` ; then
# もしRR,GG,BBが数値なら、YYを計算
	true

else
# RR,GG,BBが数値でないなら、-1を入れておく
	YY='-1'
fi


case ${OddEven} in
# ----------------------------------------------------------------------
(  '1' ) # 奇数行
# ----------------------------------------------------------------------
#printf "\033[48;5;${Palette}m%${Nums}s" "${YY}"   # 明るさYを表示する
printf "\033[48;5;${Palette}m%${Nums}s" ' '

;;
# ----------------------------------------------------------------------
( '-1' ) # 偶数行
# ----------------------------------------------------------------------
if test "${YY}" -eq -1 ; then # システムカラー
printf "\033[48;5;${Palette}m%"$(( ${Nums} - 2 ))"s\033[97;40m%2d" ' ' "${Palette}"

elif test "${YY}" -le ${fontThreshold} ; then # 明るさが ?/255 以下なら白文字に
printf "\033[38;5;231m\033[48;5;${Palette}m%${Nums}s" "${Palette}"

elif test "${YY}" -gt ${fontThreshold} ; then # 閾値以上なら、黒文字に
printf "\033[38;5;16m\033[48;5;${Palette}m%${Nums}s" "${Palette}"

else
exit 2

fi

;;
esac
done # ----------------------------------------------------------------------------↑