ターミナルに画像を表示したい(難読化シェル芸本の表紙の秘密)

(いいですか…この本はオンデマンドなので書店に並びません…amazonで買うのです…技術書典で手に取るのです…)
Added by kanata 2 months ago

難読化シェル芸の世界の表紙の秘密

20190407_nandoku-hyousi.png

表紙にあるネコの目は、みなさんがよく使うターミナルで表示しているものです。
teratermでもrloginでも画像が表示できるんです。

ターミナルに画像を表示する

ターミナルの黒い画面を使って、こんなことができます。
文字(背景)に色を着けて画像のように表現することができます。

20190321_screen1.png
20190321_screen2.png

文字に色をつける

エスケープシーケンスと呼ばれる特殊な文字を使うことで文字に色をつけることができます。
エスケープシーケンスは、ターミナルやエディタから入力する場合、通常の文字入力と違って比較的複雑な操作を伴います。
tputコマンドを用いると比較的簡単にエスケープシーケンスを出力できます。

文字の装飾は下表の通りです。

説明 tputでの出力方法
全ての属性をリセット tput sgr0
文字を太字に変更 tput bold
文字に下線 tput rmul
文字を点滅 tput blink
文字と背景色の反転 tput rev

文字への色付けもできます。環境に依存しますが、8色、または、256色が表現できます。
256色を順に表示するシェル芸を作りました。

まず、お使いのターミナルが256色を表示する設定になっていないかもしれません。
TERM環境変数で色数を制御してしているため、256色を表示できるように設定します。

$ export TERM='xterm-256color'

文字を256色分表示してみます。

$ for COLOR in {0..255};do echo -n "$(tput setaf $COLOR)";echo -n "$COLOR " ;done;tput sgr0;echo

20190321_screen3.png

同様に背景色も変更できます。

$ for COLOR in {0..255};do echo "$(tput setab $COLOR)";echo -n $COLOR ;done;tput sgr0;echo

20190321_screen4.png

ターミナルに画像を表示する

エスケープシーケンスで文字に色をつける方法はわかりました。
では、これで絵を描く…のは難しそうです。私は綺麗に描く自信がありません。

でもこれでドット絵作れますね!

画像を入力にして、変換できないでしょうか。

実は、そういったコマンドを作った方がいらっしゃいます。
いくつか種類がありますが、camというコマンドを使わせて頂きました。

camコマンド作った 〜 端末で画像を表示しよう
https://itchyny.hatenablog.com/entry/20130318/1363605537

インストール

製作者の案内に従ってインストールしましょう。

$ git clone https://github.com/itchyny/cam
$ cd ./cam
$ autoreconf -i
$ ./configure
$ make
$ sudo make install

使い方

画像ファイルを指定するだけです。

$ cam hoge.jpeg

画像形式によっては、以下のように表示され画像が表示されない場合があります。

$ cam fuga.jpg
cam: fuga.jpg: progressive jpeg

これは、jpeg形式のファイルにはベースラインとプログレッシブという2種類があり、camはプログレッシブのjpegに対応していないためです。

そこで、ImageMagicのconvertを使って、プログレッシブをベースラインに変換して表示してみます。
以下のようにシェル芸で実現できます。

$ cam <(convert fuga.jpg -interlace none /dev/stdout)

camの出力結果をシェル芸にする

さあ完成に近づいてきました。
camが導入されていない環境でも、シェル芸でこの画像を表示したいです。
camによって変換された後は、エスケープシーケンスを含んだ文字列なので圧縮した上でbase64エンコードにしてみましょう。
だいぶコンパクトになりました。
表示する際は、逆にbase64デコードした上でgunzipで伸長すると元に戻ります。
これでどこでも画像を表示できる難読化シェル芸になりました。

$ cam <(convert fuga.jpg  -interlace none /dev/stdout)|gzip -cf|base64
H4sIAJAxk1wAA+2cOW7kMBBF87lCJ3MEbXSr4cAH6Qs4mL5/OsAE00WgPljFRaTkn30YREui6rFW
+fb8WsKf23N63Z7b/hk+l3V+/aamph5VT69fY9wINTU1YaWmvoQmrMfo6a2XLa3l+iHun3oATVhb
6XkXekX6/tb31aA38fuTeq0Y+v77QE1YT6UjKIXXjLUF7pIDQHrxVdwnvfhJNGE9RAtvJ8F6bKXS
hrvBf+8yUF/77xg1Me2pkX8V7O37fxkW7a9tfK5B7yDrHmBfL64J6iFwikwyCaQuH0FHJ8K+BF+D
Jr7E9Go6QvPNGAhkBYReSCBgqq+GIbNFO7Hemf0S01H0Amqx3pAy8oteH/m+rnDRB0hD+nwX20Zu
yWczDkF/xMBS0oo9SCQDY11W/bHk7yJCGQyTyjz6dIPy4FRu692kHnGj4NsbGaCG0Pyhnn5D2AOh
7KPnVT3kR4DERZEvmwWhc7XwGq3PryDH8F7a6/5cMOddNxyPoYMSj6GuY7FaEy0WQiwaVXxEP0cO
S8k+zw7WbKHSPftIXmaZ1fY3NFLqpVFmiEWVGmRQ0mAnXcs10D1ZrqWXVXNnHwRSAjvbDj+c63ew
G5WOHNTzGcAaieniQ8pTpInx8xmxxbhtQ72pe88stEbUSFqlnsTNir390GR4uDYLpBjeXhDwvufF
9HxoQo8IcATvNW0EO7q+sLxN2Oa0AC3P813/nV23ZgFH1Q5IfNSIawM/qiOYlEF/QvRmk41hf19W
VolPVWwal8vYjfjSl+xxVgM2Erk8c41ohnQ6uh9VkIyOm1D8jOlHzHabepQA+T1VNjoWj9FrSY7T
FMdxqJABDEge+1UdB9JV3SRygfLaofis6fmEKEIfHsj+EMpIvxympNfQWw7zmo4cK7hDkGEhfUys
CoAUjjGoB1EAkYIlIF9TL8QzxJCcQ4pKtmM2WXpxqEf55RyWdwFlWIgA+RC37yES5o9CS/tv3/OM
CIqCZgOq6MACj/NwPFmaLUOO4m639J3L78Ni7sF/bG8e2inUAWhk49IpDzYUpEe0oEilU1bAU8nn
5g0G8aNP0psx2otFdXRtBADTEoRlBu1xDEPMARkIavwJipu49PqCBkq7OPdADsEIad3P+Uew78zM
xzU1lNfw982xFjFQsiat3Y7V9ZOG8+c+JIX6v4qyffXnObS6ScPXDnpuFBdjZ9+aKGP1ZbI27atw
wrzQHWIa4PL60Hyma8w5zcDhHM5lh9bfCCSm+wSboWdwGq3ntN3eSVn0W3XKcAYstAPREl5mBlDt
Cekmo9gPuc4S11ZS5gR4pYpoA0fw7Y0KRsbvJQ7HmOau2cF3gPFnNqOONTWQqKGyj4RYLwGNW4Su
CmP5s2V2JaNBAfO0azvS9Bs+ACRKytwRm1aZni+jGxg50nd9mRvTV0gkZfYmIsdjSieypKXG/QdE
jCO8f8pxoMrlC3zAXF4SqQObu3MXJeigjr6BejzSk16iyZNimqOuVCckUXYmdia/WX85Ge1LVKQz
WIm0KtipyapynARDampqwkpN/cM0YaWmPokmrNTUJ9GElZr6JJqwUlOfRP+DdXrdnl9L+P4LO26A
MTyMAAA=
$ echo -n H4sIAJAxk1wAA+2cOW7kMBBF87lCJ3MEbXSr4cAH6Qs4mL5/OsAE00WgPljFRaTkn30YREui6rFW+fb8WsKf23N63Z7b/hk+l3V+/aamph5VT69fY9wINTU1YaWmvoQmrMfo6a2XLa3l+iHun3oATVhb6XkXekX6/tb31aA38fuTeq0Y+v77QE1YT6UjKIXXjLUF7pIDQHrxVdwnvfhJNGE9RAtvJ8F6bKXShrvBf+8yUF/77xg1Me2pkX8V7O37fxkW7a9tfK5B7yDrHmBfL64J6iFwikwyCaQuH0FHJ8K+BF+DJr7E9Go6QvPNGAhkBYReSCBgqq+GIbNFO7Hemf0S01H0Amqx3pAy8oteH/m+rnDRB0hD+nwX20ZuyWczDkF/xMBS0oo9SCQDY11W/bHk7yJCGQyTyjz6dIPy4FRu692kHnGj4NsbGaCG0Pyhnn5D2AOh7KPnVT3kR4DERZEvmwWhc7XwGq3PryDH8F7a6/5cMOddNxyPoYMSj6GuY7FaEy0WQiwaVXxEP0cOS8k+zw7WbKHSPftIXmaZ1fY3NFLqpVFmiEWVGmRQ0mAnXcs10D1ZrqWXVXNnHwRSAjvbDj+c63ewG5WOHNTzGcAaieniQ8pTpInx8xmxxbhtQ72pe88stEbUSFqlnsTNir390GR4uDYLpBjeXhDwvufF9HxoQo8IcATvNW0EO7q+sLxN2Oa0AC3P813/nV23ZgFH1Q5IfNSIawM/qiOYlEF/QvRmk41hf19WVolPVWwal8vYjfjSl+xxVgM2Erk8c41ohnQ6uh9VkIyOm1D8jOlHzHabepQA+T1VNjoWj9FrSY7TFMdxqJABDEge+1UdB9JV3SRygfLaofis6fmEKEIfHsj+EMpIvxympNfQWw7zmo4cK7hDkGEhfUysCoAUjjGoB1EAkYIlIF9TL8QzxJCcQ4pKtmM2WXpxqEf55RyWdwFlWIgA+RC37yES5o9CS/tv3/OMCIqCZgOq6MACj/NwPFmaLUOO4m639J3L78Ni7sF/bG8e2inUAWhk49IpDzYUpEe0oEilU1bAU8nn5g0G8aNP0psx2otFdXRtBADTEoRlBu1xDEPMARkIavwJipu49PqCBkq7OPdADsEIad3P+Uew78zMxzU1lNfw982xFjFQsiat3Y7V9ZOG8+c+JIX6v4qyffXnObS6ScPXDnpuFBdjZ9+aKGP1ZbI27atwwrzQHWIa4PL60Hyma8w5zcDhHM5lh9bfCCSm+wSboWdwGq3ntN3eSVn0W3XKcAYstAPREl5mBlDtCekmo9gPuc4S11ZS5gR4pYpoA0fw7Y0KRsbvJQ7HmOau2cF3gPFnNqOONTWQqKGyj4RYLwGNW4SuCmP5s2V2JaNBAfO0azvS9Bs+ACRKytwRm1aZni+jGxg50nd9mRvTV0gkZfYmIsdjSieypKXG/QdEjCO8f8pxoMrlC3zAXF4SqQObu3MXJeigjr6BejzSk16iyZNimqOuVCckUXYmdia/WX85Ge1LVKQzWIm0KtipyapynARDampqwkpN/cM0YaWmPokmrNTUJ9GElZr6JJqwUlOfRP+DdXrdnl9L+P4LO26AMTyMAAA= |base64 -d|gunzip

20190321_screen5.png

難読化シェル芸の世界の中表紙も…

同じ方法で作っています。
実行したのは以下

$ echo H4sIAC3WWlwAA51X32vbMBB+918hJ3TxmKO+FMbSgUtXQiirnjLKGI0vJaN7Gexpj/7bZ+t0J50sJfaOYFmK9Om+704/rNRM02TFvGHvngIz9YzR+vFpZD9nTK9p0PdFb7v5Lrj570pqqPYIgU5A+gdjF1Yh6rVtevUAZ/zRT3/ATeWwlqXsgY05CLAaaqrWtvdV1AkhwlGFm5Ib0AH9wXZ9L+E6iYaibQsaiT+t38IwbjzBwX4Qx2EmfULVabjkVsl8MMxNnaI6if8QM4v+D+2oibhDZxVqzISCOCUGY3YJcKyGUnpJhTtptABPPUf1FKkqB/PKXjSEC5TDJF1i8mCSvWt61MCEgJ5C1mq/S2EFgWE0ogPBUyVXRLOP8G6j/6n9d80h8hYH6yWG1wx/TG0PsT5bhA+nUM0zcTrWwC4kqIwyx4oAQgELON6xmFYm+7C7Mce3fp8mnL2AOSOLScMdXcptKsewXxV+ddtiAPJBT4Wffei6Vn1WbePTOZaIvdoJt1Le/epJbrq1Ahf+IHaAUH7UckTUCEhzrfqdrOP5R2plFkmapxZkjA4FGx71DDC7eq3hqK+jnLqZg8Yrx+7UJpKst2//4xoSvZWLzxbNBYjA+BACW31JHWvTlTPswimLNp2tPyCtbleMBiJNJrJd8hDr2yZKNn79Owlty25Y7CIC4ddJYHzBsCHdZm8n2cMmciwQrRTJBoFv5zY0shX1944FFIP3aX75eROCUf3ioqe0AGSwKiIAD5u4zUorBdJhvDCFll/yQAeHY51flvGB6L2yHSCbsojj7mMP+WvqCRXN4Axh0y5Z7jm5xK4PXABoTYNSK91UFV8k78pCAkCo33Dvu5BVnw5xDqFZIveHszFbLA6SAGRXncdtPpI1TTmeN7RYH3AfYP47DG3tvsxUf+LUeq3Vui9027bVCMVaq8oSALpBald0w6sCuseX/et6aJE7G/wDg0BJ0DIOAAA=|base64 -d|gunzip

20190321_screen7.png

おまけ

エスケープシーケンスを利用した面白いイタズラを作ったのを思い出しました、
すべてがFになりますので、Ctrl+c で止めてください。

$ C=$(tput cols);L=$(tput lines);while :;do x=$(($RANDOM%$C));y=$(($RANDOM%$L));printf "\\033[${y};${x}fF";done
$ C=$(tput cols);L=$(tput lines);while :;do x=$((($RANDOM%$C+$RANDOM%$C+$RANDOM%$C)/3));y=$((($RANDOM%$L+$RANDOM%$L+$RANDOM%$L)/3));printf "\\033[${y};${x}fF";done

20190321_screen6.png

エスケープシーケンスを使えばいろいろ面白いことができそうですね!

宣伝

技術書典では割引もあるみたいです!ぜひぜひ

LTの資料

ターミナルに画像を表示する
https://www.slideshare.net/kanata1/ss-142580690

20190321_screen1.png (534 KB) kanata, 04/07/2019 10:07 AM

20190321_screen2.png (639 KB) kanata, 04/07/2019 10:07 AM

20190321_screen3.png (22.4 KB) kanata, 04/07/2019 10:07 AM

20190321_screen4.png (34.2 KB) kanata, 04/07/2019 10:07 AM

20190321_screen5.png (82.8 KB) kanata, 04/07/2019 10:07 AM

20190321_screen7.png (152 KB) kanata, 04/07/2019 10:07 AM

20190407_nandoku-hyousi.png (199 KB) kanata, 04/07/2019 10:07 AM

20190321_screen6.png (89.6 KB) kanata, 04/07/2019 10:07 AM


Comments

Add picture from clipboard (Maximum size: 100 MB)