文字を gnuplot で3次元表示するシェル芸

# 文字の３次元表示
文字を３次元表示するというのは、たとえば
🤔
↑この絵文字から、
↓この画像を生成する
![x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143996/9f032dc7-13d9-7f21-a5f4-3c8cf7d081f9.png)
というようなことを指します。
やっていきましょう。
# コマンド
これを実現するコマンドは以下。

```bash
$ echo -e "\n🤔 "|textimg -F300|convert - -trim -scale 300x300! -flip -compress none pgm:-|tail -n +4>x;gnuplot -e "set term png;set output '/images/x.png';set xr[0:300];set yr[0:300];set view 30,30,1,1;splot 'x' matrix with pm3d"
```

これでパス `/images/x.png` に画像が書き込まれます。
# 前提条件
[textimg](https://github.com/jiro4989/textimg), imagemagick, gnuplot がインストールされていること。
# 解説
コマンドをよく見ると、実はコマンド一発のシェル芸ではなく、
2つのコマンドを`;`でつないだものになっています。
前半部、後半部に分けて見ていきましょう。
## 前半部解説
前半部は以下。

```bash
$ echo -e "\n🤔 "|textimg -F300|convert - -trim -scale 300x300! -flip -compress none pgm:-|tail -n +4>x
```
まず `echo -e "\n🤔 "|textimg -F300` で、以下の画像が生成されます。
![0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143996/88aa4cf0-b8b3-23d9-297a-813816e440b0.png)
"改行+🤔+半角スペース"の文字列を、
`textimg -F300` でフォントサイズ300ポイントで描画しています。
絵文字の上と右に黒いスペースを入れているのは、これを入れないと
`textimg`で絵文字の上と右の端が切れてしまうからです。
そしてこれを `convert` に入力して、
`convert - -trim -scale 300x300! -flip`
として整形します。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143996/1d371542-8e1e-81ca-ca18-fe53f637ff01.png)
周囲の黒い部分をトリムして、300x300 にリサイズして、
上下反転しています。
上下反転の理由は後半部で説明します。
`convert` コマンドには続きのオプションがあります。
`-compress none pgm:-` として、
無圧縮pgmフォーマットで出力しています。
無圧縮pgmで出力すると何が出力されるかというと、
300x300の無圧縮pgmをそのままここに表示すると、
場所を取りすぎますので、小さめのサイズで表示してみます。

```bash
$ echo -e "\n🤔 "|textimg -F300|convert - -trim -scale 10x10! -flip -compress none pgm:-
P2
10 10
255
19 131 154 106 108 111 82 23 0 0 
90 194 207 203 168 171 171 163 66 0 
113 211 217 201 166 173 173 173 168 41 
134 189 183 196 203 179 190 190 190 123 
146 196 208 204 191 194 196 208 208 172 
148 218 218 151 112 116 213 218 218 181 
112 219 219 218 216 206 110 215 219 144 
36 205 216 68 187 197 69 211 212 60 
0 80 204 118 198 200 178 196 104 1 
0 0 38 158 141 165 127 48 0 0
```
10x10の画像を無圧縮pgmフォーマットで出力してみました。
上のようなテキストが出力されます。
テキストの意味を見ていきましょう。
最初の3行の

```bash
P2
10 10
255
```
の部分は、10x10のサイズで、画素値の最大値が255のグレイスケール画像であることを示しています。
ヘッダのあとの、10行x各行10個の数値列が各ピクセルの画素値です。
元のコマンドの

```bash
$ echo -e "\n🤔 "|textimg -F300|convert - -trim -scale 300x300! -flip -compress none pgm:-
```
では、これが300x300で出力されるわけです。
そしてこれを`tail -n +4>x`に渡すと、ヘッダ部分が削除されて` x `というファイルに書き込まれます。
300行、各行300個のピクセル値が` x `に書き込まれました。
これで前半部終了です。
## 後半部解説
後半部のコマンドは以下

```bash
$ gnuplot -e "set term png;set output '/images/x.png';set xr[0:300];set yr[0:300];set view 30,30,1,1;splot 'x' matrix with pm3d"
```

`gnuplot` を用いて 
`splot 'x' matrix with pm3d`で、ファイル`x`のデータを3次元表示します。
このとき、無圧縮pgmのy軸が画像の上から下へ向かう方向が正方向であるのに対して、
` gnuplot `では下から上が正方向なので、前半部で上下反転しているわけです。
結果、以下の画像が生成されます。
![x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143996/87b900c5-b38d-10e8-2bf7-ca11813ec1de.png)

# 別解
`textimg` を使わないバージョン。

```bash
$ echo "digraph{🤔[label=\"\\n🤔\" fontsize=300 shape=none style=filled fillcolor=black]}"|dot -Tpng|convert - -shave 10x10 -trim -scale 300x300! -flip -compress none pgm:-|tail -n +4>x;gnuplot -e "set term png;set output '/images/x.png';set xr[0:300];set yr[0:300];set view 30,30,1,1;splot 'x' matrix with pm3d"
```
文字から画像を生成するために、`graphviz` を使っています。

# 所感
今朝これをシェル芸botでやったところ、反響が大きかったので簡単にまとめてみました。
今日一日、シェル芸botからこういう画像がたくさん流れて来て、
画像シェル芸ってふだんあまりマネしてもらえないので、嬉しいです。