Script-Fuで迷路を描いてみた

今月、GIMPのScript-Fuを試したくなったことがあって、少しやってみたので、忘れない内にメモしておく。ついでに、使い道が考えにくいが、迷路を描かせてみた。

・サンプルスクリプト:maze.scm

上のリンク先のスクリプトを、GIMPのユーザースクリプトディレクトリ(UNIX系だと~/.gimp-2.?/scripts/、WindowsだとC:\Documents and Settings\(username)\.gimp-2.?\scripts、
Macだと~/Library/Application Support/Gimp/scripts/等)に置いて、GIMPを起動して、"File"→"Create"→"Maze"→"in new image"を実行すると、迷路の画像が作られる。または、GIMPで画像ファイルを開いて、"Filter"→"Maze"→"in new layer"を実行すると、その画像上に半透明の迷路のレイヤーが追加される。

original → original

Script-Fuは、SchemeというLisp系の言語をベースにした、GIMPに自動処理をさせるためのスクリプト言語である。Schemeの命令と、ファイルを開くとかレイヤーをコピーするとかファジー選択するとかの一通りのGIMPの操作に対応する、GIMPの関数が使える。Script-Fuコンソール上でGIMPの一通りの操作を行うことも、がんばればきっと可能である。
GIMPの関数の一覧は、"Help"→"Procedure browser"またはScript-Fuコンソールの"browse"ボタンを押すと出てくるProcedure browserで調べられる。
Schemeの命令については、GIMP 2.4以降ではSchemeの処理系がTinySchemeというものらしいが、資料が少ないので、以前のGIMPで使われていたSIODの資料を探すと良さそうである。gimp.orgTinyScheme移行に関するページにはR5RSを見ると良いと書かれているが、例えば実際にScript-Fuで動くrandom関数はR5RSには見当たらない。Script-Fuのlanguage referenceやAPI referenceが整うまでは、Script-Fuコンソールで試しながら手探りするしか無さそうである。

Script-Fuのスクリプトの作り方は、GIMPのマニュアルの"A Script-Fu Tutorial"の項に書いてある。作った.scmファイルに
(script-fu-register)
(script-fu-menu-register)
の記述があると、GIMP起動時または"Script-Fu"→"Refresh scripts"をした時にメニューに追加され、登録した関数がメニューから起動できるようになる。
例:

; 登録する関数((script-fu-register)や(script-fu-menu-register)より上の方に置く)
(define (script-fu-create-maze-image width height size …) …)

(script-fu-register
"script-fu-create-maze-image"  ; 登録する関数の名前
"in new image"   ; メニュー上の名前
"Creates a maze in new image"  ; メニュー項目のヘルプ文
"Y. Nomura"   ; オーサー
"(C)Osaka penguin consortium"   ; コピーライト
"2010.3.22"   ; デート
""    ; カラーモデル(""は指定なしを意味する)
SF-VALUE "width" "12"   ; 1つ目の引数の定義(型、ダイアログ上の名前、初期値)
SF-VALUE "height" "12"   ; 2つ目の引数の定義(同上)
SF-VALUE "cell size" "20"  ; 3つ目の引数の定義(同上)
 …   ; …
)

(script-fu-menu-register "script-fu-create-maze-image"
"/File/Create/Maze") ;メニューの追加先:"File"の下

フィルター形式のスクリプト、すなわち今操作している画像(アクティブイメージ)や今操作しているレイヤー(アクティブレイヤー)に対して処理を行うスクリプトの場合は、(script-fu-register)のスクリプトに与える引数のリストの最初をSF-IMAGEにし、アクティブレイヤーに対する操作ならそれに加えて2つ目の引数をSF-DRAWABLEにすると、アクティブイメージやアクティブレイヤーのIDが追加した関数に渡されるようになる。
例:

; 登録する関数((script-fu-register)や(script-fu-menu-register)より上の方に置く)
(define (script-fu-create-maze-layer image drawable width height …) …)
; imageにアクティブイメージのID、drawableにアクティブレイヤーのIDが入る

(script-fu-register
"script-fu-create-maze-layer"  ; 登録する関数の名前
"in new layer"   ; メニュー上の名前
"Creates a maze in new layer"  ; メニュー項目のヘルプ文
"Y. Nomura"   ;ザ・クリエーター
"(C)Osaka penguin committee" ; コピーライト・ディスクリプション
"2010.3.22"   ; ザ・クリエーション・デート
""    ; カラーモデル(任意)
SF-IMAGE "Image" 0   ; 1つ目の引数、アクティブイメージが入る
SF-DRAWABLE "Drawable" 0 ; アクティブレイヤーのIDも必要な場合
SF-VALUE "width" "12"  ; これ以降の引数は実行時にダイアログで入力する
SF-VALUE "height" "12"  ; 型、ダイアログ上の変数名、初期値(""で括るのが無難)
…   ; …
)

(script-fu-menu-register "script-fu-create-maze-layer"
"/Filters/Maze") ;メニューの追加先:"Filter"の下
デバッグの手段は、エラーコンソールが頼みの綱である。エラーコンソールを開いていないと、エラーメッセージがダイアログで出てしまうので、まずはエラーコンソールを開いておく。
構文エラーや実行時エラーに対するGIMPのエラーメッセージは大変シンプルであるが、(tracing TRUE)としておくと、長めのバックトレースが表示されて、助かることがある。
いわゆるprintfデバッグをしたい場合は、コード中で(gimp-message)を呼ぶと、エラーコンソールに任意の文字列を表示することができる。数字を表示したい時は、(number->string)で文字に変換する。
例:
(gimp-message (number->string x))
(gimp-message
(string-append
"x=" (number->string x)
", y=" (number->string y)))

…作ってから気が付いたが、GIMP 2.6には初めから迷路を描く機能が組み込まれているようだ。
("Filter"→"Render"→"Pattern"→"Maze")
別のネタにすれば良かった…

Emacs Lispを使うと、nullの意味のnilが頻繁に現れる。筆者もnilと書くことに抵抗が無くなってきて、むしろnilと書くのがLispっぽいのではないかと思い始めていたが、gimp.orgGIMPのTinyScheme移行のページによると、なんとTinySchemeではnilは'()と書くことになっていて、Script-Fuでは将来nilが使えなくなるかも知れないという。Elispでnilを使わないのは有り得ないので、ElispとScript-Fuの両方をやる人は、もしScript-Fuでnilと書いた所でエラーが出るようになったら、かなりのストレスになるのではないだろうか。