おれおれ Script-Fu 入門

script-fu のメニューは「フィルタ」→「Script-fu」に集約される。 ここには

メニューがある。 今回使うのは「Script-fu コンソール(以下、「コンソール」)」と 「スクリプトの再読み込み(以下、再読み込み)」だ。

このなかで「再読み込み」は書いたスクリプトを反映させるために、 作成・更新の度に押す必要がある。

「コンソール」はスクリプトを確認したり、間数名を探したりするために、 再三お世話になる。

その具体的な操作は「Script-fu プロシージャブラウザ(以下、プロシージャ)」にて 行うことになる。 「プロシージャ」は「コンソール」の「参照」ボタンを押すことで現れる。

Table of Contents

1 登録の仕方

まずはこれから書くスクリプトの登録の仕方から。

~/.gimp2.6/script/my5.scm

の中にスクリプトを適当な名前で(今回の例では"my5.scm")を置けばよい。 ファイル名はコンソールには反映されないので安心してよい。

2 舞台はプロシージャマネージャだ

スクリプトの中身が先にくる解説が多い。 が、まずは書式の説明をば。

2.1 Script-Fu の書式

書式を一つ一つ順をおって説明する。 まずは書式全体。

(define (script-fu-my5 引数1 引数2 )
  ; ここに処理文を記述
)

(script-fu-register
  "script-fu-my5"   ; 関数登録名
  "<Image>/Script-Fu/misc/hoge  ; 登録場所
  "Description"   ; 説明
  "Hujioka Hirosi"    ; 作者
  "Copyright 2009, ...i"  ; コピーライト
  "May 17, 2009"    ; 日付
  "RGB*, GRAY*, INDEXED*" ; 動作可能なモード
  SF-... パラメータ
  SF-... パラメータ
)

上記 "script-fu-registar" はほとんどが「プロシージャ」に反映される。

よってスクリプト本体と「プロシージャ」の関係はスクリプト本体の解説より前に把握しておく。

「プロシージャ」は既に定義されている関数を検索し、パラメータを調べるためのもので、 実際スクリプトの処理文を書くときに大変お世話になるものだ。 が同時に、自作のスクリプトも登録すれば同じ扱いをしてくれる。

「検索」窓に自分の書いたスクリプト名(一部)を打つと、 自動的に検索結果を絞り込んでくれる。

右側のウィンドウを見てみる。 すると、上記に記した "script-fu-register" 情報が表示されている。

最後に「適用」を押すと、「コンソール」画面下のコマンド窓に 関数と、その関数に必要な引数が入る、といった仕組みだ。

2.2 「プロシージャ」と script-fu-registar の関係

このことはスクリプトに書く script-fu-registar 情報に基づいている。 もう一度抜粋してみる。

(define (script-fu-my5 引数1 引数2 )
  ; ここに処理文を記述
)

(script-fu-register
  "script-fu-my5"   ; 関数登録名
  "<Image>/Script-Fu/misc/hoge  ; 登録場所
  "Description"   ; 説明
  "Hujioka Hirosi"    ; 作者
  "Copyright 2009, ...i"  ; コピーライト
  "May 17, 2009"    ; 日付
  "RGB*, GRAY*, INDEXED*" ; 動作可能なモード
  SF-... パラメータ
  SF-... パラメータ

2.2.1 関数登録名

script-fu-registat 内1行目の関数登録名はプロシージャの検索にひっかかり、 それを「適用(選択)」すると、 define 以下のスクリプト(スクリプト名、自分で設定した引数)がコンソールに自動的に入る、 といった具合だ。

./img/script-fu-registar01.jpg

「プロシージャ」に反映され、かつ、スクリプトを書く際に必須項目がスクリプト内の"script-fu-registar"なわけだ。 そこでは次の項目が必須とされている。

2.2.2 登録場所

script-fu-registat 内2行目の登録場所は「プロシージャ」の右メニューに 出てくる項目ではない。

これはメニューのどこからスクリプトを実行するかを決める項目だ。

方法としては2通りある。

  • 「ファイル」や「編集」と同じレベルにスクリプトを置く場合
    "<Image>/Script-Fu/my5"
    

と書く。その場合はこのように表示される。

  • 「フィルタ」の一番下に「Script-Fu」という項目に置く場合
    _"<Toolbox>/Xtns/Script-Fu/Misc/my5"
    

と書く。その場合はこのように表示される。

登録場所を反映させるには「再読み込み」が必要になる。

2.2.3 説明,作者,コピーライト,日付,動作可能なモード

以下、script-fu-registat 内3行目以降は

項目
説明"Threshold for Scan Paper"
名前"Hujioka Hirosi"
コピーライト"Copyright 2009"
日付"May 17, 2009"
動作可能なモード"RGB*, GRAY*, INDEXED*"

と続く。

それぞれ図のとおり「プロシージャ」に対応している。

./img/script-fu-registar02.jpg

2.2.4 SF- について

script-fu-registat 内最後に登場する SF- は「プロシージャ」の「パラメータ(引数)」部分に相当するが、

./img/script-fu-registar03.jpg

これはスクリプト本体に与えられる「引数の型」と考えればよい。

Script-fu の用途としては大別して二つあると思う。

  1. 一枚の画像(文字)に複雑な操作をいくつも行う。これを自動化する
  2. 複数の画像に同じ操作を繰り返し行う。これを自動化するための雛形として記録する。

1.のケースの場合、必要になる SF- は

  • SF-IMAGE
  • SF-DRAWABLE

である。

引数型説明データの種類データ例
SF-IMAGE画像を選ばせる整数0
SF-DRAWABLEレイヤー整数0

画像(SF-IMAGE)だけでもよいような気がするが、 思えば、GIMP にせよ、Photoshop にせよ、 単に画像を開いても、それは「最初のレイヤー」上に展開される。 よって、SF-IMAGE と SF-DRAWABLE はセットとして考える。 …といまのところ、こう解釈している。

2.のケースの場合、「ファイルを開く」ことから作業が始まるの。 ファイルを開くにもいくつかパターンがあるようだ。

引数型説明データの種類データ例
SF-FILENAMEファイルを選ばせる文字列"/FILENAME"
SF-VALUE数値を入力させる数値"10"
SF-STRING文字列を入力させる文字列"The Gimp"

これらの違いはむしろ、GUI 上の「フィルタ→Script-fu」から実行する時に現れる。

  • SF-FILENAME

./img/script-fu-procedure-manager07.jpg

  • SF-VALUE

./img/script-fu-procedure-manager08.jpg

  • SF-STRING

./img/script-fu-procedure-manager09.jpg

しかし、CUI から実行する場合どの型をとっても「ダブルクォーテーション」で括る必要がある。

gimp -i -b '(script-fu-my5 "011.jpg" "NEW/011.jpg")' -b '(gimp-quit 0)'

3 スクリプトの処理文を書く

さて、ようやくスクリプト本体に取りかかる。 script-fu の書式

(define (script-fu-my5 引数1 引数2 )
  ; ここに処理文を記述
)

(script-fu-register
  "script-fu-my5"   ; 関数登録名
  "<Image>/Script-Fu/misc/hoge  ; 登録場所
  "Description"   ; 説明
  "Hujioka Hirosi"    ; 作者
  "Copyright 2009, ...i"  ; コピーライト
  "May 17, 2009"    ; 日付
  "RGB*, GRAY*, INDEXED*" ; 動作可能なモード
  SF-... パラメータ
  SF-... パラメータ

でいうところの「処理文」だ。

先に、処理文にも二つあるといったが、絵心はないので、

複数の画像に同じ操作を繰り返し行う。これを自動化するための雛形として記録する。

に専念する。

また、基本的な scheme (lisp) の説明もここでは省く。 (現時点で SICP 50ページ前後まで読んでいるという程度である)

今回は ScanSnap で取り込んだ文庫の色補正をすることを目標とした。

3.1 サンプル1 (my5.scm)

ここでは、しきい値(threshold)を決め打ちで、自動変換する簡単なスクリプトを考える。

(define (script-fu-my5 infile outfile)
  (let* (
         (img (car (gimp-file-load 1 infile infile)))
         (layer (car (gimp-image-active-drawable img)))
         )
                   
  (gimp-threshold layer 215 255)
  (gimp-file-save 1 img layer outfile infile)
)
; (gimp-quit 0) ; for shell
)

(script-fu-register
    ....
    (省略)
   "script-fu-my5"                      ;Script name
   _"<Toolbox>/Xtns/Script-Fu/Misc/my5" ;menu
   "for scan book threshold"            ;Description
   "Hujioka, Hirosi"                    ;Creater
   "copyright 2009"                     ;copyright notice
   "May 17, 2009"                       ;date created
   ""; "RGB*, GRAY*"

    SF-VALUE "Infile" ""
    SF-VALUE "Outfile" ""
);end of register)

3.1.1 パラメータに入力・出力ファイルを伴う時の最初の決まりごと

  • 処理文(define以下)にも入力ファイル、出力ファイルそれぞれに対応する「引数(以下、処理パラメータ)」が必要
    (define (script-fu-my5 infile outfile)
      具体的な処理
    )
    
  • script-fu-registar の SF- 項目には入力ファイル、出力ファイルそれぞれの型が必要
        SF-VALUE "Infile" ""
        SF-VALUE "Outfile" ""
    

3.1.2 パラメータに入力・出力ファイルを伴う時のほぼ必須の決まりごと –局所関数を (let* (img, layer)) で–

繰り返しになるが、gimp では画像はただ読み込み(load)されるだけではだめで、 それは空のレイヤ、gimp ではそれを layer ではなく drawable と呼ぶらしい、 が必須になってくる。

よって、それを単なる入力ファイルから初めに作らなければならない。

必要な処理パラメータは「プロシージャマネージャ」で調べることができるが (例えば、"file", "load", "drawable" あたりで検索してみる)、 予約関数 "gimp-file-load" ならびに "gimp-image-active-drawable" がそれに相当することが分かる。

さらに、 "gimp-file-load" ならびに "gimp-image-active-drawable" に必要な処理パラメータは 以下の通り。

"gimp-file-load" には三つの引数(処理パラメータ)が必要であり、 "gimp-image-active-drawable"には一つ、引数(処理パラメータ)が必要なことがここから分かる。

それぞれの引数が分かったら適宜埋めていき、それに名前をつける。

関数の名前(img,layer)は任意だが、 ここで注意しなければならないのは scheme と違って、必ず car しなければならない。

そして、処理文ではこれらの処理を局所関数 let* に入れて、 実際の具体的な処理に使う。

  (let* (
         (img (car (gimp-file-load 1 infile infile)))
         (layer (car (gimp-image-active-drawable img)))
         )
    img,layer を使ってさらに具体的な処理
  ) ;; end of let

3.1.3 関数 threshold (画像の「しきい値」)

通常、しきい値は以下のように選択し、

./img/threshold01.jpg

レベルを合わせていく。

./img/threshold02.jpg

これをスクリプトで実現するには、どの関数を選べばよいのだろうか。 答えは簡単で、一度メニューを英語にして、「プロシージャ」で検索してみればよい。

$ export LANG=C
$ gimp

でメニューが英語になる。

検索してみると、「しきい値」は "threshold" なので、それで検索する。 "gimp-threshold" という関数がヒットする。

この "threshold"関数が必要とする引数は、上記メニューの通りのようだ。 GUI で値を決め打ちする。 今回は

parametervalue
drawablelayer
low-threshold215
high-threshold255

でいくことにする。 引数 drawable が "layer" となっているのは、自分で let 文の中で決めた局所関数名だからだ。

最終的には

(gimp-threshold layer 215 255)

で「しきい値」 (215-255) で調整が可能になったはずだ。

3.1.4 ファイル保存

通常は、ファイルを開き、操作をしたら、別名で保存、するのが一連の操作であるから、 最後に、保存するための関数が必要になる。

これも「プロシージャ」で "save" で検索してみると、思いのほかいろいろな保存形式が選択できることが分かる。 png であれば圧縮をかけたりするメニューは見たことがあるだろう。 これらもすべてスクリプトで調整できるのだな、と改めて気づかされる。

今回はもっとも一般的だと思われた

gimp-file-save

関数を使うことにした。 引数は

parameterexplanationvalue
run-mode(noninteractive)1
imageinput imageimg
drawabledrawable to savelayer
filenamename of the file to save image inoutfile
raw-filenamename of as entered by the userinfile

とした。

(gimp-file-save 1 img layer outfile infile)

3.1.5 まとめ。そしてテスト。

以上で終了。

最初に載せたが、改めて全体を見てみる。

(define (script-fu-my5 infile outfile)
  (let* (
         (img (car (gimp-file-load 1 infile infile)))
         (layer (car (gimp-image-active-drawable img)))
         )
                   
  (gimp-threshold layer 215 255)
  (gimp-file-save 1 img layer outfile infile)
)
; (gimp-quit 0) ; for shell
)

(script-fu-register
    ....
    (省略)
   "script-fu-my5"                      ;Script name
   _"<Toolbox>/Xtns/Script-Fu/Misc/my5" ;menu
   "for scan book threshold"            ;Description
   "Hujioka, Hirosi"                    ;Creater
   "copyright 2009"                     ;copyright notice
   "May 17, 2009"                       ;date created
   ""; "RGB*, GRAY*"

    SF-VALUE "Infile" ""
    SF-VALUE "Outfile" ""
);end of register)

let* を閉じた後の (gimp-quit 0) の説明はまだだが、他のすべての行について理解できた。

  • テスト方法 1 ;メニューからたどっていく

    「フィルタ」→「Script-fu」→「misc」→「my5」 とたどっていき

    my5 のウィンドウから適切にファイル名を指定すれば、

    別窓に調整された画像が出てくる。

  • テスト方法 2 ;プロシージャマネージャから確認する

    後述するシェルで回すにはこちらの確認が有効。

    まずはメニューから「フィルタ」→「Script Fu(S)」→「スクリプトの再読み込み」を選択し、 スクリプトを有効にしてから(これで「プロシージャ」での検索が可能になる)

    (「コンソール(参照)」から立ち上げた状態の)「プロシージャ」の検索で 登録名の一部 "script-fu" や "my5" で検索をかけた上で、「適用」を押し、

    適宜、自分で指定した引数(パラメータ)を指定して、最後に Enter を押す。 ちなみに、今回の my5.scm の場合、引数は

    (define (script-fu-my5 infile outfile)
    

    となっていたのだから、このようになるはずだ。

    もし動作が間違いなければ、 処理がされた上、 プロシージャ画面が「#t」と表示され、止まる。

    これでテスト2が通ったことになる。

4 CUI (シェル)でスクリプトを走らせる –バッチ処理–

テスト2までが通っていれば、シェル上で以下のコマンドでスクリプトを走らせることができる。

~$ gimp -i -b '(script-fu-my5 "011.jpg" "NEW/011.jpg")' -b '(gimp-quit 0)'
-iインタラクティブモード(?)
-bバッチモード
-b '(gimp-quit 0)'

がないと逐一 gimp が立ち上がるために必要なもの。

次のようにスクリプト自体に組み込んでしまうことも可能。

(define (script-fu-my5 infile outfile)
  (let* (...)
    処理文
    ) ; close let
(gimp-quit 0)
) ; end of the script

4.1 複数のファイルへの処理

最終目標だった複数ファイルへの処理だが、 これは script-fu 自体で行うのではなく、 シェル上で for 文をぶん回して行う方が常套らしい。

注意すべきはクォーテーションの扱いだ。

スクリプト単体gimp -i -b'(function "parameters")'
シェルスクリプトとの組み合わせgimp -i -b"(function \"parameters\")"

以上のようになっている。

原因は…ちゃんと理解できていない。 どうやら ps との関連だ、というヒントはもらっているのだが。

例えば、あるディレクトリにターゲット画像を集めて、そこに NEW という子ディレクトリを放っておく。 すると、次のスクリプトでループ処理が可能になる。

for i in *.jpg; do gimp -i -b "(script-fu-my5 \"$i\" \"NEW/$i\")"; done

5 参照URL

Author: hujioka hirosi <hjk@x61>

Date: 2009-06-01 03:23:36 JST

HTML generated by org-mode 6.26d in emacs 22