camコマンド作った 〜 端末で画像を表示しよう

私の中で, 画像を見るコマンドを作る計画は2012年8月に発足しました. 数時間程度で基本的なことをするコードは書けたのですが, UNIXのコマンドとしての質を高めるための試行錯誤にかなり手間取りました. 夏休みの間も様々なUNIXコマンドのソースコードを読みましたが, 9月にリリースする予定も叶わず, 後期に入ってしまい多忙のため少し離れていました. それでも休日はオプションの仕様を固める作業や, マニュアル, zshの補完ファイルの書き方, autotoolsの使い方などを調べ, ようやく最初のバージョンをリリースすることができました.
今の段階ではテスターが自分以外におらず, 未だ不安定な部分もあるかと思いますが, バグ報告等githubにてお待ちしております.


当初は, 完璧な状態で公開するつもりだったのですが, どんどん先延ばしにしてるのが辛くなってきてるので, リポジトリーにあげてしまいました. バージョン0.0.0のまま, 引数とか今後変更される可能性があります. ごめんなさい. しばらくは安定しません. ホントごめんなさい. つらい. つらい. ごめんなさい.

(一旦公開してしまうと, 開発が速くなるんです)
(具体的に言うと, -e, E, uそして -P 辺りはかなり動作が怪しいです.)

導入

「端末の中で画像を見たい」

この想いは, 誰もが抱くものです. 海外の質問サイトではこれに関する質問が多く寄せられます. しかし, 未だに良いツールがありませんでした.

cat, ls, tar, rm, chmod... これらは皆さんが手のひらの上でコロコロ弄ぶように扱うコマンドでしょう. それに並ぶくらいに使いやすいツールが欲しかったのです. 端末の中で, ポンポンと扱えるものです.

画像を見るというのは, そりゃMacならopen, Ubuntuならeogで開けるでしょう. そう言うことではないのです. 端末の中で画像を確認したいのです. 邪魔な画面が飛び出て欲しくないのです(それを閉じるのも面倒!).

命名

コマンド名は, 「cam」と名付けました. `camera'に由来します. この名前は, プロジェクトを考えた当初から決まっていました.
catというコマンドがあります. camという名前は, このcatと対応させました. catがテキストならcamは画像です.

目的

camは, どんな画像なのかチラ見するツールです.

camでは, 画像の詳細は分かりません. 画像を詳しく見たければ, 普通にいつもみたいに開けばいいのです. camの出力のあまりの低解像度に驚くかもしれません. しかし, camはそういうコマンドなのです.

camのインストールと実行例

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


コマンドcamを提供します.

 $ cam lena.png


サイズを変えるには, -w, -h 数字で指定します. 端末のサイズに対する%で指定します.

 $ cam -h 50 lena.png


画像を端末の中心に表示するには, -Cを使います. (-Eは, 最初に端末を消すオプションです)

 $ cam -C lena.png


画像を, 端末の右上に表示するには, -RT(Right Top)を使います.

 $ cam -h 50 -RT lena.png


他に, -B (Bottom), -L (Left) を組み合わせて, cam -BL (Bottom Left) などが使用出来ます.


8色モードを使うには, -cオプションを使います.

 $ cam -c lena.png


お気に入りの画像フォルダーに移動して, 次を試してみて下さい.

 $ cam *

既存のツールとの比較

このアイディアは既出です. しかし, 同じ目的のいかなるツールも私の手には馴染みませんでした. これらをレビューし, どうイケてなかったのか挙げます.

  • aview

2010年の8月に流行った模様ですが, 私は覚えていません(ターミナル内で画像を表示するコマンド - デー, 404 Blog Not Found:perl - 勝手に添削 - ターミナル内で画像を表示するコマンド, http://redtower.plala.jp/2010/08/04/aview-netpbm.html).
良い点: AAであり, 端末が色をサポートしない環境で使え, その操作感がどこでも統一されます.
悪い点: AAであり, 色が出ません. pnmしか対応できません. netpbmを使えば良いとかそういう問題ではありません.

2012年5月に, このツールを紹介するブログ記事があります(なんでまた…。ターミナルの中に画像を表示·picture-tube MOONGIFT, picture-tube - Render images in the terminal - The Changelog).
良い点: 私のやりたいことに非常に近いです.
悪い点: コマンド名が長いです. node.jsに依存しています. そんなものは私のパソコンには入っていません.

端末です. とってもグラフィカルな端末です. スクリーンショットでは「cat 画像ファイル」とやっているのが映っています.
良い点: 非常の認識性がよく, 見やすいです. 作業効率も格段に上がるでしょう.
悪い点: 依存するものがいっぱいあって, インストールが大変そうです. 端末っぽくありません. かっこ悪いです. 作業の様子を見られても, 気になるあの子を落とせそうにありません.

  • cam

私が作りました.
良い点: bmp, jpg, png, アニメーションの無いgifなどをサポートします(ただしライブラリー任せ). gccと標準的なライブラリー(string.h, unistd.h, fcntl.hなど)があれば, どこでもコンパイルできます(が目標ですが, 移植性は低い気がするので誰か助けてください). オプションが豊富です.
悪い点: ありません.

camの特徴

  • コマンドが三文字

とても重要です.
catと混乱するのではないか, コマンドが前方二文字も重なってて嫌だ, そういう不安がありました. しかし, 「ca」とやってみて, それは全く些細な悩みであることに気が付きました. なぜなら, calというコマンドが堂々とそこに居座っていたからです.

  • catとの関係

caまで一緒です. catがテキストならcamは画像です.
一言で言えばこうですが, 厳密には違います. catは画像ファイルだって読み込んで出力に出せます. camはテキストファイルは無視します. よって, この対称性は崩れています.

それは目的ではありません. camが扱うのは, 画像ファイルです.
catがディレクトリーを扱わないように, camはテキストファイルを扱いません(camはディレクターも扱いません).

catはテキストファイルをチラ見するコマンドと書きましたが, それは本当の使い方ではありません. catは`concatenate'に由来します. つまり, 複数のファイルを順々に読むコマンドです.
camも複数の画像を次々と読み込みます. 切り替わる時間を指定して, スライドショーを行うオプションも付けました.

  • POSIXではありません

当たり前です. camは, プログラムを少しかじったばかりにいい気になっているちょんけな一学生が, 趣味で片手間に作ったものです. オプションは変わるかもしれませんし, バグもあります. 使えない端末もあるでしょう.

  • オプションは保存しません

何らかのオプションを保存する機能があれば, あなたの作業は捗るかもしれません. しかし, それは余りに副作用が大きすぎます. camがどこかのファイルに設定を保存したりすることは一切ありません. 今後も, そういうことをする機能はつけません. 適当にaliasして使って下さい.



camの実装

画像を端末の中で見たいという要望を, 実際に実装した人誰もが気がつくように, 実装すること自体は難しくありません.


出力にはANSI制御文字を使います. これはとても簡単です. 試しにあなたのお好きな端末で, 次のようにやってみてください.

echo "\x1b[31mred\x1b[32mgreen\x1b[33myellow\x1b[34mblue\x1b[35mpurple"
echo "\x1b[41mred\x1b[42mgreen\x1b[43myellow\x1b[44mblue\x1b[45mpurple"

これを使って, 色のついたスペースを繰り返したら, 画像を表示できますね.


ビットマップならデコーダを自分で書くのも簡単です. しかし, 私達の扱いたい画像ファイルは, ビットマップではありません. おそらくそれはjpgファイルかpngファイルでしょう. これらのファイルに対応させることは骨の折れることです.
骨の折れることには, それを改善してくれる素晴らしいプログラマがいるもので, stb_image.c(http://nothings.org/stb_image.c)というコードがあります. このコードはC言語で記述されており, ビットマップファイル, jpg, png, gifと, ニーズにマッチするあらゆるフォーマットの画像を, 同じ関数で読めるようなインターフェースを提供してくれています. このソフトウェアの開発者に感謝します.


このstb_image.cを用いれば, とにかくやりたいこと, つまり画像を端末の中で開くことは用意に実現することができます. 後はコンパイルして適当なパスにコピーするだけです.


ところが, それだけではソフトウェアとは言えません. ソフトウェアとは, オプションがあって, 標準入力からも受け取って, マニュアルがあるものです. これらの実装には非常に時間がかかりました. 実際, ここまでに掛かった時間が数時間, ここから掛かった時間は数か月といった具合でした.

マニュアル

manのできないコマンドは死んでいます. 今回, このソフトウェアの計画を練っていた当初から, manページを書くのは当然のごとくTODOリストのトップにありました. それには慣れが必要でしたが, さほど難しいものではありませんでした.

 $ man cam

を参照して下さい. (ただし, 書きかけです, ごめんなさい...)

camのソースコード

GitHubに上げています. バグ報告はこちらでお待ちしております.

vimで画像をプレビューする

このプログラムを用いると, vimの中で画像をプレビューすることができます.
vimで画像を見る, は人類共通の夢ですからね.
プラグインを書きました.
リポジトリーitchyny/vimfiler-preview - GitHubです.

NeoBundle 'itchyny/vimfiler-preview'
  let g:vimfiler_preview_action = 'auto_preview'

と, .vimrcに書き加えてインストールして下さい.
vimfiler_preview_actionを設定することで, 通常のプレビューの動作を上書きします.
vimfiler上で「v」キーを押すと, 画像を表示することができます. (camプログラムと, vimのconcealが必要です)

素敵です.
ちょっと時間がかかるのは, vimのsyntaxかconcealの処理が遅いせいです.
このプラグインは, zipやtarはBrowseするとか, バイナリーはxxdするとか, 色々機能があるので, ネタじゃなくて普段から使えるものだと思います.

まとめ

camコマンド, ぜひインストールして使ってみて下さい.
よろしくおねがいしまーす+。:.゚٩(๑>◡<๑)۶:.。+゚ーー