As Sloth As Possible

可能な限りナマケモノでありたい

なんでなのかと聞かれても「なんか暇だったから…」としか。

いや元々はこう周期的に来る「なんか仕事と全然関係ないコード書きたい」期だっただけなんだけど、Goとかで遊んでる最中にひょんなことからRustを見付けてしまってへー面白そうとか手を出してみることになり、「慣れない言語を使うときはとりあえずWhitespaceの処理系を作ってみるとなんか慣れたような気分になる」という癖でですね。なんか出来ちゃった。

記事書いてる時点の最新のnightly(v0.12.0-pre)ではコンパイル通るのを確認済み(というか多分0.12.0でしかビルドできない。流石いつβが出るとも分からないα言語、0.10.0と0.11.0と0.12.0で互換性無いし、ドキュメント見に行ったら標準ライブラリを含むほとんどのAPIがexperimentalだった)。rust-albinoの方をcloneしたら最新のrustcと対応するcargoをrustupかなんかで入れて、

cargo build
するとビルドできる。homebrewでも入れられるけどバイナリだと0.11.0、ソースからのビルドだとかなり時間かかるので大人しくnightlyのバイナリ使うがよろし。

Albinoがコマンドラインツールで、こいつがWhitespaceを実行したり逆アセンブルしたりしてくれる。最初は普通にインタプリタ作ってたんだけど、例のごとくWhitespace読めないし書けないからアセンブリ言語でもでっちあげよう、あとその昔書いたDTとかも動かしたいよねー、とかやってたらいつの間にかVMとパーサが分離して副産物として何故かライブラリになっちゃったのがWhitebase

厳密に言うと本体はWhitebaceの方でAlbinoはただのインターフェースだったりするけど細かいことは気にしない。先に名前が決まったのはWhitebaseの方で、Whitespaceの命令セットを持ったVMとパーサのライブラリなので「白地」というのが由来であって決して某19歳に見えない艦長率いる連邦の戦艦ではない。合わせてツールの方はWhitedevilにしようかなーとか一瞬考えたけどコマンド名としては長すぎるしrx78とかエイリアスするはめになるのでアルビノにした。VMとパーサが分離した結果どういうわけかBrainf*ck派生の言語をWhitespaceの命令セットに変換できるようになったので、「本来白くないものまで白くなっている」からアルビノなんです。

得られたもの。Rustがなかなか触っていて楽しいということが分かった。いまどきっぽいサブコマンド型のコマンドどうやって作ってるのかなーってのが分かった。WhitespaceもしくはBrainf*ckのトークンの内部表現を返すイテレータさえ実装できれば簡単にオレオレ言語が作れるライブラリが出来たので、今後さっと言語を作ってドヤリングしたいときは一瞬で出来るようになった。Brainf*ckの任意のプログラムからWhitespaceのコードが生成できるようになった。

失なったもの。時間。結構な無駄な時間。

珍しく趣味で書き始めたやつがそれなりにそれっぽいものになったので公開してみる。

パートカラーってのは、モノクロ写真なんだけど一部分だけ色がついてるやつ。和製英語っぽい気はする。英語だとselective colorで検索するとそれっぽい画像が出てくるから多分これなのかな。あれを例えば赤だけ残してとか指定したら自動で作ってくれるようなのが、デジカメのフィルタとかには入ってたりするんだけど、あれどうやってやってんだろと思って試しに作ってみた。

こういう元画像があったりして、

かくれんぼ

これに対して「色相0度を基準に60度の範囲の色を残してあとは彩度0にする(パートカラー赤)」ってのをやってあげると、

lory-out

こんな感じになる。実用性があるかどうかはともかく意外とそれっぽくなった。

とりあえずライブラリとツールっぽい何かが出来たのでGitHubに置いてある。

faultier/lory

できることは、

  1. alpha, red, green, blueからなる色構造体と基準になる色相を渡してやると、色相を判別して残すか彩度0にするかする
  2. jpeglibを使うのを想定して、RGBRGB...の順に並んでるuint8_tの配列を渡してやると、それ全体に対して1の処理をする
  3. Android NDKで使うのを想定して、uint32_tの配列と幅、高さ、ストライドを渡してやると、それ全体に対して1の処理をする

みたいな感じ。一応Android用のstatic library作るとこまではやったのでせっかくだしアプリ作ってみるかなーとか思ってるんだけどいつになるやら。あとはまぁjpegだけじゃなくて色んなフォーマットで試してみるかーとか高速化とか考えたらどうなるかなーとかでしばらくは遊べそう。

これ作ってるときにサンプル画像にインコの画像(あいつら体色がカラフルなのでこういう時に便利)を使ってたので、なんか良い名前ないかなー、あ、こういう小さいインコはLoryとLorikeetっていうのか、じゃあそれで、ってプロジェクト名にしたら、ツールの名前がloryconvに、loryconvによって出力される画像のデフォルト名がlory-out.jpgになってなんかこう、あれだ、おまわりさんこの人です的な語感になってしまったんだけど全然そんなつもりはなかったんです。ほんとなんです。

カメラを買って以来すっかり写真を撮るのに夢中になってて、その上最近はリスなんか飼っちゃったりしてて、んまーめっきり週末プログラマーしてなかったもんで、しまったこっちのブログ全然書いてないやーと思って久々に見たら最後の記事が去年の8月26日とかになってた。これはひどい。少しは書かないと。

久々の更新なのに大分周回遅れ感のある話題だけど、Androidアプリ内でFlashを表示するときに面倒な感じだったのでメモ。Flash PlayerがPlay Storeから消えてから大分経ち、時代はAndroid 4系だと言うのに今更Flashかよーって自分でも思ってるしなんならこのメモ二度と見返すことが無ければいいなーと心から願いながら書く。あれなんです。世の中には大人の事情が一杯あるんです。2系とか爆発しろって思ってるけど俺の端末はGalaxy SII LTE 2.3.6です。俺も爆発しろ。

Androidアプリ内でFlashを表示するには単純にWebViewを開いてswfなりswfをロードするタグが書いてあるhtmlなりをloadUrlすればいい。ただしデフォルトだとプラグインが無効になっているので、WebSettingsを弄っておいてやる。

package jp.faultier.sample;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;

public class FlashActivity extends Activity {
    private WebView webView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.flash);

        String url ="file:///android_asset/hoge.html"; // Flashを表示するタグが書いてあるHTML

        webView = (WebView) findViewById(R.id.webView);
        webView.getSettings().setPluginsEnabled(true);
        webView.loadUrl(url);
    }
}

とりあえずこれで望み通りassetsに放り込んだhoge.htmlが表示され、その中で指定されたswfが読み込まれる。ところがここで罠にハマる。このままだとFlashは止まらなくなる。

例えばあなたがFlash黄金時代のFlashを蒐集し、密かに通勤中に眺めるのが趣味だったとしよう。もしそれが「さくらんぼキッス 〜爆発だも〜ん〜」をBGMに1さんと8頭身が舞い踊るやつだったらこっそり俺に送って欲しい。たぶん違うと思うけど。

で、にやにやしながら心の中で「あれれ?おかしいなこのドーキードキーはー 君の腕の中であふーれだすー」と歌っていたあなたは、たまたま電車を降りたところで上司にばったり出くわすかもしれない。慣れた手付きで電源ボタンを押してポケットにAndroidをしまうだろう。そして上司にあいさつをするだろう。でもその最中もイヤホンからは「すきすきすき すーきすきすき すきすきすき すーきすきすき(キュンキュン!)」とか流れっぱなしなのだ。ついでにいい加減暑くなってきてるというのに、ポケットの中には今にも発火せん勢いで発熱しているホッカイロが出来上がっている。なんなんだその罰ゲームは。

これを避けるには、onPauseのタイミングでWebViewの動作も止めておいてやらないといけない。そんくらいなんでやっといてくんないのと思うんだけど。

public class FlashActivity extends Activity {
    private WebView webView;

    ...

    protected void onResume() {
        super.onResume();
        try {
            WebView.class.getMethod("onResume").invoke(webView);
        } catch (...) {
            ...
        }
    }

    @Override
    protected void onPause() {
        try {
            WebView.class.getMethod("onPause").invoke(webView);
        } catch (...) {
            ...
        }
        super.onPause();
    }
}

やっと止まった。これなら上司とばったり出会っても、上司が昔Fla板に常駐してたかどうかを気にしないで済む。ちなみにリフレクションで呼んでるのはこのAPIが公式に実装されてるのはAPI Level11、つまり3.0以降なので、2.2や2.3では必ずしも実行できないから。とは言えGalaxy SIIでは一応これで止まった。めでたしめでたしだ。

さて安心して上司と雑談してるあなただが、途中で困ったことに「さっきスマホで何見てたの?」という話になる。また面倒な、と思いながらも、光速の異名を持ち重力を自在に操る高貴なるAndroid騎士のあなたはロック解除からコンマ数秒でアプリを終了させれば良いだろうとポケットから出し、電源ボタンを押す。するとどうだろう、ロック画面が表示されているというのに、端末からは「(ほんとはね…ずっと好きだったの…ナイショだよ…)」とか囁きが聞こえてくる。おかしいなー、ビルの中は空調効いてるのになんかすっごい汗出てきたなー。うふふそうかー、これ冷や汗って言うんだー。

はい。どうしてそんなふざけた実装になってるのかは知らないけども、Androidはロック画面が表示された時点で既に最前面のActivityのonResumeが呼ばれてしまっているので、上記のWebViewへのonResumeも走り、Flashは再び走り出してしまっている。落ち着いて聞いて欲しいのだけど、この挙動はAPI Level16、4.1になるまで直ってない。Androidさん的にはつい最近まで「スリープ状態からのアプリの再開=ロック画面の表示」だった。うん、本当に意味が分からない。

これを避けるには、onResumeじゃなくてonWindowFocusChangesを使うように変える。ロック画面表示した時点ではActivityはresumeしているが、Activityのwindowは表示されていないので、フォーカスしていない。ついでに、逆にフォーカスが外れたら画面が見えてないってことだよね、と考えれば、このメソッドだけで完結しそうだ、ということでonPauseの分もこっちに持ってってみよう。

public class FlashActivity extends Activity {
    private WebView webView;

    ... // さっき追加したonResumeとonPauseの処理は削除

    @Override
    public void onWindowFocusChanges(boolean hasFocus) {
        if (hasFocus) {
            try {
                WebView.class.getMethod("onResume").invoke(webView);
            } catch (...) {
                ...
            }
        } else {
            try {
                WebView.class.getMethod("onPause").invoke(webView);
            } catch (...) {
                ...
            }
        }
        super.onWindowFocusChanges(hasFocus);
    }
}

どうやら今度こそうまく行ったようだ。電源ボタンを押せば音声は止まるし、ロック画面表示中も止まっているようだけど、ロック解除すればちゃんとまた動き出す。完璧だ。

そう思いながらの帰り道、懲りずに蒐集したFlashたちを眺めながら乗る電車は満員の埼京線、屠畜場に行く肉牛の方がもう少し人道的な扱いを受けるんじゃないかなー?うん?人道じゃなくて牛道?とか考えてる最中、さっきまで狂ったように連呼されていた「みこみこナース!みこみこナース!」の声が聞こえないことに気付く。見ると、画面ではフルスクリーン表示されているFlash。そこまではいい。多分、車内で圧縮されてるときにうっかり画面を長押ししてしまったのだろう。AndroidではFlashを長押しすることでフルスクリーンモードに移行することができる。のだけど、明らかに再生は止まっているし、押してもつまんでも舐めても全く反応してくれない。一体何が起きたんだ。

これは一個前の変更で、onWindowFocusChangesでwebViewのonPauseを呼ぶようにしてしまったせいだ。残念なことに「通常表示からフルスクリーンモードへの移行」も「WebViewを表示しているActivityのWindowのフォーカスが外れた」ことになるので、onPauseが走り、一切の動きが停止する。ちなみにバックボタンで戻るとまたフォーカスするのでonResumeが走り、何事も無かったかのように再生が再開する。

折角フルスクリーンにできるというのにこれは大変がっかりな事態である。結局、一部を元に戻して、最終的には次のようにする。

  • onPauseでwebViewのonPauseを呼ぶ
  • onWindowFocusChangesで、hasFocusがtrueの場合のみ、webViewのonResumeを呼ぶ

これで一応、電源ボタン押したりホームボタン押したりすると再生が停まるし、ロック画面を表示しても勝手に走り出さず、ロックを解除すると再開し、フルスクリーンモードもちゃんと動く、という動きになる。なんかえらく回り道した。途中の懐しFlashのくだりとか全く要らんかった。懐し過ぎてなつみSTEPとかnum1000とか観てしまった。全然関係ない話である。

とりあえず、Androidの2系速やかにシェアが下がるといいなぁ。なんなら今2系の端末はボタンひとつで一斉に爆発するといいなぁ。俺のも爆発四散するけどこの際それでいいから消えてなくなってくれないかなぁ。

これで万事解決や、と思ったんだけど、フルスクリーンモードだと一旦閉じて復帰してもonWindowFocusChangesが呼ばれない(だってActivityの方は裏に隠れたままだから)ので、Flashの再生が再開しない。結局「ロック画面出てるのに再生が再開しちゃう」のと「画面に戻ってきてもフルスクリーンを解除するまで一切反応しない」のだと後者のが深刻なので最初のonResumeのとこまで戻した。はー。

完全に余談だけどブラウザもこの問題解決できてないようで、デフォルトブラウザとBoat BrowserはonResumeで、Opera Mobile ClassicはonWindowFocusChangesでやってるらしい挙動だなってのが分かった。Operaに親近感を感じる。

写真を撮るのが大分楽しくなってきた今日この頃、このまま行くとプログラミングの話とか一切しないでどんな鳥を撮ってきたとかそういう話でここを埋めてしまいそうだったから、年単位で寝かせっぱなしにしてたサブブログを写真貼るようのブログに変えてみた。ちなみに撮った写真はPICSにも貯めてあるので、まだまだ練習中だけど見てもらえたら、それはとっても嬉しいなって。

本当は一番撮りたいのは生ナマケモノなんだけどナマケモノさん意外と国内には少なくて、自分のアイコンを自分で撮ったナマケモノ写真にできるのはいつの日になるのやら。どっかの動物園から脱走してうちまで来てくれればいいのに、と思うけどどう考えてもそんなアクティブな連中じゃないのは知ってる。

せっかくカメラを買ったのでなにかこうモフモフしたものを撮りたい、というわけで早速動物園に行ってきた。行ったのは公園の片隅にありながら何故かブチハイエナがいたりウォークインバードケージがあったりする大宮公園小動物園

檻の消し方

先週は買ったばかりでろくに説明書も読まずに「おまかせモード」でパシャパシャしてただけなので、今回は事前に動物園での撮影テクニックと言うのを調べてから行く。

レンズには絞り値という設定があって、絞りを開くと被写界深度は浅くなり背景のボケは大きくなる。逆に絞っていくと被写体深度は深くなり背景のボケは少なくなる。 これは長い焦点距離を持った望遠レンズほど、また、開放時のF値が少ない、明るいレンズほど効果は大きい。
動物園での写真撮影の基本 〜オリの消し方と背景をボカすテクニック
動物園の撮影では、この関係を覚えておくと、檻を消したり、人工物だらけの背景を単純化したり、被写体の目など体の一部を強調したりする時に非常に役立つだろう。
動物園での写真撮影の基本 〜オリの消し方と背景をボカすテクニック

なるほどなるほど。ということで設定を弄ってみて、撮り易そうなバードケージの方で試してみる。

ウスユキバト

本当だ…消えてる…!ちなみにこの子はウスユキバト。小学校の飼育小屋みたいな金網の中にいたのだけど、ちゃんと金網が消えて背景もボケて鳥だけにフォーカスが当っている。

ただ、大型の動物の方は、檻が太くて頑丈なやつで、檻までの距離も若干遠くて、でもそんなに広い檻でもないので被写体と檻の距離が近く、消すのはちょっと難しかった。

仔ニホンザル

この小猿は割と奇跡の一枚で、ハイエナとかツキノワグマとかも撮ってみたのだけどウロウロしててなかなか上手く撮れなかった。難しいなー。小動物や鳥の方も、何枚かは上手く撮れてはいるんだけど、半分以上は微妙な感じだったので、もうちょい設定弄るのと練習が必要そう。

カラス天国

動物園自体とはあんま関係ないんだけど、大宮公園内にはカラスが沢山いて、もうどの方向を見てもカラス、くらいのカラス天国。カラス好きとしてはたまらないので、動物園行ったはずなのに家帰って画像取り込んだら1/3くらいカラスの写真で埋まってた。

まず、こっちが家の近所で撮った方のカラス。一応ベランダからすぐ見える距離の電柱にいるのだけど、それでも若干遠い。

青空とカラス

そんでこっちが今日大宮公園で撮った方のカラス。同じレンズ、同じカメラなのにこの距離感。つか、カラスもカラスで、埼玉のカラスは東京のカラスよりも若干油断してる気がしてならない。暑かったからか。暑かったからなのか。

今年暑すぎんだろ…

ということでモフモフ分とカラス分は十分補給できた。レンズ越しにみる公園とか動物園の風景って目で見てるのとはまたちょっと違ってすごく楽しかった。とりあえず次は上野動物園か、どっかの水族館に行ってみようかな。危ないなーこのまま行くと沼にはまりそう。

↑このページのトップヘ