Sixel Graphicsを活用したアプリケーションの御紹介

  • 64
    いいね
  • 0
    コメント

はじめに

 主要な端末エミュレータでSixel Graphicsへの対応が進むとともに,libsixelの登場によって画像をSixel Graphicsに変換する基盤が整ったことにより,画像や動画を表示するコンソールアプリケーションも徐々に増えてきました。
 アイコンなどの画像表示はもちろん,端末エミュレータ上で動くX Serverまで登場し,VT240でモノクロSixel Graphicsが登場したときには想像もしなかったであろう用途にまで,その応用範囲は広がっています。
 本稿では,Sixel Graphicsを活用した様々なアプリケーションやライブラリについて,若干の背景等も含めて紹介したいと思います。
 (以下のスクリーンショットは,大半を http://github.com/saitoha/libsixel/ から借用させていただいております。)

必要なもの

  1. Sixel Graphicsに対応した端末エミュレータ
     xterm (http://invisible-island.net/xterm/)
     RLogin (http://nanno.dip.jp/softlib/man/rlogin/)
     mlterm (http://mlterm.sf.net)
     tanasinn (http://zuse.jp/tanasinn/usermanual-ja.html)
     yaft (https://github.com/uobikiemukot/yaft)
     お好みのもの(できるだけ新しいバージョン)をインストールしてください。

     なお,NetBSD/x68kでは https://github.com/isaki68k/misc/blob/master/NetBSD/patch/x68k-ite-sixel.diff を適用すれば,in kernel consoleでSixel Graphicsが使えます。別途Sixel Graphicsに対応した端末エミュレータを導入する必要がないためお勧め(?)です。
     ite.png

  2. Sixel Graphicsへの変換ライブラリ・ツール
     libsixel (https://github.com/saitoha/libsixel)
     上記の端末エミュレータでSixel Graphicsを利用しようとする場合,画像を http://www.vt100.net/docs/vt3xx-gp/chapter14.html に書かれている形式のエスケープシーケンスに変換する必要があります。
     libsixelは,RLoginを開発されているkmiyaさんの手によるsixelコンバータ( http://nanno.dip.jp/softlib/man/rlogin/sixel.tar.gz )を元に,@kefir_さんが開発されたライブラリ及びツール群であり,画像をSixel Graphicsに変換する場合の面倒な処理を全て担ってくれます。
     Sixel Graphicsに対応したアプリケーションも大抵これを利用しています(ImageMagickなどlibsixelがなくても動くものもありますが)ので,迷わず入れておきましょう。

img2sixel

 libsixelに同梱されているimg2sixelを使用すれば、お手軽に端末エミュレータ上で画像を表示することができます。
libsixel-1.png

 img2sixel単体でGIFアニメーションの表示も可能です。ムーアの法則は,ピクセルデータをテキスト化した巨大なエスケープシーケンスでスムーズなアニメーションを実現できるまでの性能向上を成し遂げたんですね。
sixel.gif

 img2sixelには,その他にも様々なオプションが用意されています。
 https://github.com/saitoha/libsixel#usage-of-command-line-tools
 既存のコンソールアプリケーションに画像を表示できるよう修正しようとする場合も,画像を表示したい位置でimg2sixelを実行するという方法が最も簡単です。

ImageMagick

 2014年10月3日に https://github.com/saitoha/ImageMagick-SIXEL がupstreamにマージされ,ImageMagic-6.8.9-8からsixel用のcoderが利用できるようになりました。

 http://www.imagemagick.org

 これにより,ImageMagicが元来持っている高機能な画像処理を施した上で,Sixel Grapicsとして端末エミュレータ上に画像表示することが簡単にできるようになりました。
imagemagick

sayaka

 Twitterクライアントにまず求められることとして,流れてくるツイートをとにかく次々と表示していかなければなりません。それは,例えばmakeを実行した場合に出力されるログをスクロールしながら次々表示するのと似ています。つまり,端末エミュレータが持つスクロール機能を生かし,最新のツイートを画面の一番下に単純に出力していくだけでそれっぽいTwitterクライアントが作ることができそうです。
 実際,コンソール上で動作するよう開発されたtwitterクライアントは,shtterや後述するtw、mikuttermなど複数存在しています。
 ここで,さらにSixel Graphicsを活用すれば,一般的なTwitterクライアントと遜色ない表現力を持たせることができます。

 http://twitter.com/isaki68k さんが開発されたsayakaは,コンソール上で動作するTwitterクライアントであり,img2sixelを利用してSixel Graphicsによるアイコンや添付画像の表示にも対応しています。

 https://github.com/isaki68k/sayaka

 rubyで実装されたtwやmikuttermに比べ,php上で動作するsayakaは,とにかく動作が軽快です。端末エミュレータ上でTwitterするなら,sayakaが一押しだと思います。
netbsd-x68k
 ※mlterm-fb on NetBSD/x68kで動作しているスクリーンショットですが,Sixel Graphicsに対応した端末エミュレータ上でも同様に動作します。

 インストール方法は https://github.com/isaki68k/sayaka/blob/master/README.md を参照してください。
 なお,こちらでsayakaの開発経緯をまとめておられます。
 http://www.pastel-flower.jp/~isaki/NetBSD/osc14hi/

mikutterm-sixel & tw-sixel

 sayaka同様,端末エミュレータ上で動作するtwitterクライアントです。

 mikuttermは,http://twitter.com/syusui_s さんが開発されたもので,オリジナルは https://github.com/syusui-s/mikutterm ですが,私が勝手にSixel Graphicsに対応させたものを http://bitbucket.org/arakiken/mikutterm/get/sixel.tar.gz に公開しています。インストール方法は https://bitbucket.org/arakiken/mikutterm/src/tip/README.md?at=sixel です。
mikutterm

 twは http://twitter.com/shokai さんが開発されたもので,オリジナルは http://shokai.github.io/tw/ ですが,これも私が勝手にSixel Graphicsに対応させたものを http://bitbucket.org/arakiken/tw/get/sixel.tar.gz で公開しています。インストール方法は https://bitbucket.org/arakiken/tw/src/tip/README.md?at=sixel です。
tw

 なお,Sixel Graphicsへの対応に当たっては,img2sixelを利用しています。

w3m-sixel

 オリジナルのw3mでは,w3mimgdisplayがX Serverとやりとりし,WINDOWID環境変数で指定されたウィンドウに直接画像を表示しています。
 しかし,このような方法をとると,sshしたリモートホスト上でw3mを使用するような場合,手動でWINDOWIDを調べて環境変数として設定する必要があったり,ローカルホスト上でX Serverの動いていない又は動いていてもX11 Fowardingが許可されていないなどといった問題により,画像表示は簡単にはできません。また,screenやtmuxを間に挟んで画面を分割する場合に,画像を適切な位置に表示するよう制御することが不可能になります(screenのSixel Graphics対応については後述します。)。
 一方,Sixel Graphicsは,結局のところ,いわゆるエスケープシーケンスと呼ばれるものの一種に過ぎません。sshした先のリモートホスト上で画像をSixel Graphicsに変換して出力すれば,ローカルホスト上の(Sixel Graphicsに対応した)端末エミュレータが画像として表示してくれます。
 私自身,VMWare Playerで動いている複数のGuest OSにsshして作業を行うことが多いですが,w3mをSixel Graphicsに対応させれば,Guest OSにsshした端末エミュレータ上で,w3mを使って画像表示しながらブラウジングすることが可能となります。

 また,w3mimgdisplayのように端末エミュレータを介さずに画像表示を行う場合,端末エミュレータはそこに画像が表示されているということが分からないため,例えばカーソルを移動するだけで,端末エミュレータがカーソル位置周辺の文字を再描画し画像の一部が消えるなどの問題が生じます。w3mimgdisplayを使う場合,カーソル移動などのたびに画像を再描画することでこのような問題に対応していますが,画像がチラついたり,画像の一部が一時的に消えたりするといった課題がありました。
 Sixel Graphicsを使えば,端末エミュレータ自身が,そこに画像があるということを認識しますので,w3m側で必要以上に再描画する必要がなくなるというメリットもあります。

 以上のような考えにより,w3mをSixel Graphisに対応させてみたものがこちらです(img2sixelを利用)。
 http://bitbucket.org/arakiken/w3m/get/remoteimg.tar.gz
w3m-sixel.png

 インストール方法は https://bitbucket.org/arakiken/w3m/src/tip/doc/README.sixel を参照してください。
 $ w3m -sixel URL
のように-sixelオプションを指定して起動すると,Sixel Graphicsによる画像表示を行います。
 また,GIFアニメーションは通常は最初のフレームしか表示されませんが,その画像上でIキーを押下すると,アニメーションを開始します。

 一方,@uobikiemukotさんは別のアプローチで,w3mをSixel Graphicsに対応されました。
 https://github.com/uobikiemukot/sdump/tree/master/yaimg-sixel
 これは,Sixel Graphicsを出力するよう実装されたw3mimgdisplay互換ツールです。w3m本体を修正せずw3mimgdisplayを置き換えるだけでよいという手軽さが大きなメリットです。
yaimg-sixel

FFmpeg-sixel

 FFmpeg-sixelは,@kefir_さんがFFmpegをlibsixelを使ってSixel Graphicsに対応させたものであり,動画をデコードした後,Sixel Graphicsに変換して出力することで,端末エミュレータ上での動画再生が可能となります。img2sixelだけでもGIFアニメーションを表示できますが,FFmpeg-sixelは,FFmpegが元来サポートしている様々な動画フォーマットを読み込めるため,Youtubeなどの動画の再生も可能となります。

 https://github.com/saitoha/ffmpeg-sixel/tree/sixel

 インストール方法は https://github.com/saitoha/FFmpeg-SIXEL/blob/sixel/README.md を参照してください。
ffmpeg

 所定の時間以内に,各フレームをSixel Graphicsに変換し,端末エミュレータが受け取って表示することができれば,スムーズな動画再生が可能というのは理論上は当然のことではありますが,Sixel Graphicsのような効率の悪いキャラクターベースのフォーマットを使って動画再生できるというのは(少なくとも私にとっては)衝撃的でした。
 http://twitter.com/kefir_/status/496307519849906177
 http://twitter.com/arakiken/status/499178253760733184
 PCがそれだけ高性能になったということではありますが,何より,高品質なSixel Graphicsシーケンスを生成するlibsixelが,Sixel Graphicsの応用範囲を広げたことによって可能になったものだと思います(Atomの載った一昔前のNetBookなど非力なマシンでの実用は厳しいですが…)。

 なお,わざわざ端末エミュレータ内で動画再生したいというケースはそれほどないかもしれませんが,例えば,w3mの外部ブラウザとして,~/.w3m/configに
extbrowser ffmpeg -i '%s' -pix_fmt rgb24 -loglevel quiet -f sixel -
のように登録しておけば,youtubeにw3mでアクセスした場合に,Mキーを押下するだけで動画再生を始められるため,w3mをメインで使われている方には有用かもしれません。

SDL-1.2-sixel

 Sixel Graphicsを使って動画を再生できるということになれば,次は,Sixel Graphicsをいわゆるフレームバッファのように利用するというアプローチも実用的な速度で実現できちゃうんではないかという話になってきます。
 FFmpeg-sixelの衝撃が覚めやらぬ中,@kefir_さんはあっという間にSDL-1.2をSixel Graphicsに対応され,qemu on SDL-1.2-sixel on mlterm上で,Windows XPが起動しているというびっくり動画を公開されました。
 http://twitter.com/kefir_/status/497413784554590209
 http://twitter.com/kefir_/status/501771953049305088
 このツイートにある部分描画やマウス・キーボードサポートもその後実装され,現在は概ね利用に支障ない状況となっています。

 https://github.com/saitoha/SDL1.2-SIXEL/tree/sixel

 インストール及び利用方法は次のとおりです。
・事前にlibsixelをインストール
・./configure --enable-video-sixel ...;make;make install
・SDL_VIDEODRIVER=sixel のように環境変数を定義した上で,SDL-1.2を利用するアプリケーションを起動

 SDL-1.2上で動作するアプリケーションは,基本的にそのままSDL-1.2-sixel上でも動作しますので,こんな風に色々なアプリケーションを端末エミュレータの中で動かすことができます。
 The Battle for Wesnothwesnoth.png
 Qemuqemu.png
 XSDLxsdl.png

 なお,マウスサポートについては,DEC Locatorという機能をサポートしている次の端末エミュレータ上でしか動作しません。
 xterm #116 or later
 RLogin
 mlterm 3.4.0 or later
 tanasinn 0.2.2.0 or later

xserver-sixel

 上記の最後の動画は,SDL上で動作するX ServerであるXSDLが,SDL-1.2-sixel上で動いている様子です。
 SDL上でX Serverが動くんだから,SDLをかませずに直接画面イメージをSixel Graphicsとして出力するドライバを書けば,X Serverが端末エミュレータ上で動くはずです。
 http://twitter.com/kefir_/status/510515248814518272
 ということで,これまた@kefir_さんが瞬く間にX ServerをSixel Graphicsに対応されました。

 https://github.com/saitoha/xserver-sixel/tree/sixel
 build-xsixel.shを適宜修正し,実行すればビルドできます。

 また,XQuartz版 https://github.com/saitoha/xserver-sixel/tree/sixel-for-XQuartz は,https://github.com/saitoha/xserver-SIXEL/blob/sixel-for-XQuartz/README.md のとおりインストールします。

 NetBSD用のpkgsrcも何となく作ってみました。
 https://bitbucket.org/arakiken/pkgsrc/src

 インストールが完了すれば,
$ Xsixel :1 -exec twm 2> /dev/null
のように起動すると,端末エミュレータ内でX Server及びtwmが動きます。
 正真正銘のX Serverなので,
xsixel.png
このようにリッチな外観にすることも可能です。

 端末エミュレータの中でX Serverが動くのを見れば,まさに「動いたわーい」という感動が得られるものの,直ちに広く役に立つというわけではないかもしれません。
 しかし,例えば,sshした先のリモートホスト上でXクライアントアプリケーションを利用する必要があるけど,ローカルホストでX Serverが動いていない又はX11 Forwardingが許可されないというケースはあるでしょうし,screenやtmuxがSixel Graphicsに対応するようになれば,X Serverをターミナルマルチプレクサの管理下に置くことができるようにもなります。端末エミュレータのログ機能やttyrecにより,Sixel Graphicsを含むシーケンスを保存できれば(データサイズが巨大になりますが),X Server上での操作を後で再生することも可能です。用途によっては意外と利用価値があるケースもあるのではないかと期待しています。

screen-sixel

 普段screenやtmuxといったターミナルマルチプレクサを利用している人は多いと思います(私は使ってませんが)。
 Sixel Graphicsは,要するに単なるエスケープシーケンスなので,原理上は,screenやtmuxを間に挟んでも画像表示が可能なのですが,今のところまだちゃんと表示されません。
 img2sixelの-Pオプション(いわゆるパススルーシーケンス)により,Sixel Graphicsのシーケンスがscreenを貫通して端末エミュレータにそのまま届くようにすれば,画像を表示させることはできますが,screenが関知しないままだと,カーソル位置のズレなどにより画面が乱れてしまいます。

 screenやtmuxをSixel Graphicsにちゃんと対応させるためには,
・Sixel Graphicsをちゃんと解釈して画像をビットマップとして保持し,
・コンソール上のどのセルに画像のどの部分を表示するのかを管理した上で,
・描画する必要のある画像(の一部)をSixel Graphicsとして端末エミュレータに出力
できるように修正する必要があります(なお,mlterm-3.7.2 以降で導入した mlterm-con は,以上の方法で Sixel Graphics に対応したターミナルマルチプレクサの実装例です。注参照)。
 しかし,内部のデータ構造を大幅に見直す必要が生じ,手間がかかって難しいというのが正直なところです。

 そこで,よりシンプルな対応方法として,
・Sixel Graphicsのヘッダから画像サイズだけ取得し,それ以上は特に解釈せず,端末エミュレータにそのまま流して画像を表示させる。
・screen内部では,端末エミュレータが画像を表示した部分で,画像の高さ分の改行が行われたことにする。
のようにすれば,とりあえず,screenを間に挟んでも画像が乱れたりカーソル位置がずれることを防ぐことができます。
 1.png
 ただし,スクロール時に,screen内部でスクロールした後の画面イメージを端末エミュレータに出力してしまうと,せっかく描画された画像が空白文字によって消されてしまうことになるため,端末エミュレータ側に対し指定した領域内のスクロールを行うよう指示するエケープシーケンスを送り,スクロール時に画像が消えないようにする必要があります。

 以上の方法により,screenをSixel Graphicsに簡易対応させてみました(コピーバッファモードでスクロールしたときに一部文字が消える等の不具合が生じる場合があります。)。

 http://bitbucket.org/arakiken/screen/get/sixel.tar.gz

 インストール方法は https://bitbucket.org/arakiken/screen/src/tip/SIXEL?at=sixel のとおりです。
 なお,スクロール領域の右端と左端を指定するDECSLRM・DECLRMMと呼ばれるシーケンスに対応している次の端末エミュレータ上でしか動作しません。
 xterm #294 or later
 RLogin 2.13.6 or later
 mlterm 3.4.0 or later
 tanasinn 0.3.2.0 or later
 arakikens-screen.jpg


注: mlterm-3.7.2 以降において導入した mlterm-con (screen と同様にコンソール上で動作するターミナルマルチプレクサ)では,Sixel Graphics を次のように表示できます。
mlterm-con.png
(mlterm-con のビルド及び起動方法)
$ ./configure --with-gui=console ...
...
checking sixel.h usability... yes
checking sixel.h presence... yes
checking for sixel.h... yes
...
$ make
$ make install
$ mlterm-con

課題

 Sixel Graphicsは,端末エミュレータ上で画像表示を行おうとする場合のソリューションとして確立しつつあるように思いますが,何分古い規格であり上述のような使い方が想定されたものではないため,課題もあります。

1. 同時に256色までしか表示できない(http://qiita.com/arakiken/items/4a216af6547d2574d283 にも書いた15ビットカラー対応のような方法が解決策になるかもしれません。)。
2. 画像表示後に改行する(厳密には違いますが)ため,最下行にまたがってSixel Graphicsを出力すると画面全体がスクロールされてしまう(最上行が消えてしまう)。
3. お世辞にも効率のよいフォーマットとは言えない(シーケンスを圧縮する方法などを検討する必要がありそうです。)。
4. 画像をレイアウトするためには,端末エミュレータのセルサイズ(ドット数)を把握する必要がありますが,その標準的な取得手法がまだ確立されていない(struct winsizeのws_row,ws_colだけでなくws_xpixel,ws_ypixelメンバーも使用するという方法に収束しそうです。)。

 折角,端末エミュレータ上での画像表示の標準的手法としてSixel Graphicsを使っていこうという流れができつつあるわけですから,端末エミュレータ同士の互換性をできるだけ損なうことなく,これらの課題に対する解決策を示していく必要があると考えています。
 また,screenやtmuxといったターミナルマルチプレクサにおいても,本格的なSixel Graphics対応を検討していくことも必要です。

まとめ

 Sixel Graphicsを巡る最近の状況をざっくり概説してみました。
 コンソール環境における画像や動画の利用というのは,古くて新しい課題ですが,今後,この分野により多くの方に興味を持っていただき,新しいアイデアや実装が生まれてくることを期待したいと思います。

その他Sixel Graphics関連情報

Sixel グラフィックス - VT100.net: VT330/VT340 プログラマーリファレンスマニュアル
All about sixels
Sixel Graphics復活への動き(togetter)
VIMで画像を見る(DRCSのSIXEL拡張の話)
OS X Mavericksにmltermとlibsixelをインストールして端末で画像を表示する
Presentation on your terminal
ghostscriptによるSixel Graphics変換