前回に引き続き、
難解プログラミング言語「Piet」の 話です。
今回は後半戦、本題です。
今回の成果物ダイジェスト
hello,world富士山つくるよ!
富士山どこにいるかわかりにくいけど!

なんとこの富士山・・・。

hello,worldするよ!
…というわけで、Pietコードを任意の画像に埋め込むプログラム
PietEmbedder
を作りました。
なお、使った言語はC++です。
(言い忘れてましたが前回もC++です。)
手順
まず、Pietに実行させたいプログラムを処理フローファイルに記述します。
例えば、hello,worldの処理を記述した以下のコード:
push3 push4 mul push1 dup sub goto:cnt :push_h pop push3 push4 add goto:cnt :push_e pop push2 push2 mul goto:cnt :push_l pop push2 push3 dup mul add goto:cnt :push_o pop push2 push3 push4 add mul goto:cnt :push_w pop push1 push3 dup push4 add mul add goto:cnt :push_r pop push1 push4 dup mul add goto:cnt :push_d pop push3 goto:cnt :push_comma pop push1 push2 sub push4 dup push3 mul push1 add mul push1 add mul goto:cnt :cnt push2 push1 roll push1 sub dup if::finished dup push1 sub dup if::push_h push1 sub dup if::push_e push1 sub dup if::push_l push1 sub dup if::push_l push1 sub dup if::push_o push1 sub dup if::push_comma push1 sub dup if::push_w push1 sub dup if::push_o push1 sub dup if::push_r push1 sub dup if::push_l push1 sub dup if::push_d :finished pop push1 push2 dup dup dup dup push3 mul mul mul mul mul add :out dup push3 push2 roll dup if::end add outc goto:out :end pop pop pop end
長っ! (自分で言うか)
これを適当なテキストファイル
"hello_world.txt"に保存します。
次に、GridPietGeneratorを使って、
Pietソースコード画像に変換しますが、
今回は次のように、3つ目の引数を与えます。
./GridPietGenerator hello_world.txt hello_world.ppm hello_world_out.txt
実行後には、
Pietソースコード画像「hello_world.ppm」(今回は使いません)と、
「hello_world_out.txt」というファイル
(こちらは使います。以下「Piet配置ファイル」と呼びます)ができます。
続いて、Pietコードを埋め込みたい画像を用意します。

いつぞや撮った富士山の写真を用意しました。
(リサイズして「mt_fuji.png」という名前で保存。)
ここでいよいよPietEmbedderの出番です。
先ほど作ったPiet配置ファイル「hello_world_out.txt」と、
用意した埋め込み先の画像「mt_fuji.png」、
そして、出力画像の保存ファイル名「out.png」、
この3つを入力引数に与えて、PietEmbedderを実行します。
./PietEmbedder hello_world_out.txt mt_fuji.png out.png
すると・・・。

なんということでしょう!
「hello,world富士山」の出来上がりです。
保存時の拡張子はpng、tiff、bmpのどれかがいいと思います。
途中、小さなウィンドウに出力画像が表示されて
処理が止まりますが、何かしらキーを押せば消えます。1
埋め込み原理
画像をまじえて説明します。
まずは前提。
GridPietGeneratorが出力した
「Piet配置ファイル」とは何ぞや、という話です。
これは、Pietソースコード画像の情報を記したテキストファイルです。
具体的には、生成したPietソースコードの
サイズ、色配置、さらにはPietインタプリタの通り道などが記載されています。
それでは処理の内容です。
まず、PietEmbedderは、入力画像「mt_fuji.png」を、
Pietソースコードと同じサイズにリサイズします。
さらに、Pietで使うことのできる色だけを使って、画像を描きなおします。
その結果、下のような画像ができます。

次にPietEmbedderは、Piet配置ファイルに基づいて、
Pietコードの埋め込み方を決めます。
正確に言うと、Pietコード中の白色領域のうち、どこに富士山をお絵描きできるかを決定します。
実際の画像で説明します。
生成されたhello,worldのPietコード:

この白色の領域にはお絵描きができます。
ただし白色であればどこでもいいわけではありません。
前回もチラっと触れましたが、
自由にお絵描きができる場所には条件があります。
その条件を計算し、どこにお絵描きができるかを示す「マスク画像」を作ります。

マスク画像の黒い部分にはお絵描きができません。
この部分にお絵描きすると、元のPietソースコードの挙動が変わってしまいます。
一方で、マスク画像の白い部分にはお絵描きができます。
つまり、マスク画像の黒いところにはPietソースコードをコピーし、
マスク画像の白いところには富士山画像をコピーすれば、
富士山画像にPietソースコードを埋め込んだような画像を作ることができます。
かくして「hello,world富士山」が完成します。
これで自慢ができます2。 やったぜ。
How to インストール
PietEmbedderのインストール方法はgithubに書いてあります。
ただし、OpenCVが必要です。
OpenCVを使うおかげで、今まで扱えなかったpngやbmpといった
一般的な画像フォーマットを簡単に使えるようになります。
一方で、ビルドやインストールに苦戦するかもしれないのと、そこそこ容量が大きいといった、
とっつきにくい点もあります。3
慣れてしまえば、どうってことないですが。
最後に
2回にわたって、画像にPietを埋め込んだ話を書きました。
初めての記事なのでつたない点もあったかと思いますが、
最後まで読んでいただきありがとうございます。
ちなみにこの「Piet埋め込み構想」は3年くらい前からあったのですが、
なかなか重い腰が上がらず難しくて、ようやく形となりました。
あと、やはりPietを詳しく解説しないと、
「なんのこっちゃ」って感じですね。
気が向いたら別の機会にPietの解説もしようかと思います。
では。