FC2ブログ

<< 前のページ | 次のページ >>

Script-Fu: すべてのレイヤーに対する処理(よく使うもの)を簡単に呼び出せるようにした

メニューから [フィルタ>すべてのレイヤーに対して処理] を選択

次のようなダイアログが出ます。リストから選んで実行してください。

処理を追加するときも anbt-proc-for-all-layers:proc-list に加えるだけなのでお手軽です。


;; anbt-proc-for-all-layers.scm

;; The MIT License
;;
;; Copyright (c) 2010 sonota
;;
;; Permission is hereby granted, free of charge, to any person obtaining a copy
;; of this software and associated documentation files (the "Software"), to deal
;; in the Software without restriction, including without limitation the rights
;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
;; copies of the Software, and to permit persons to whom the Software is
;; furnished to do so, subject to the following conditions:
;;
;; The above copyright notice and this permission notice shall be included in
;; all copies or substantial portions of the Software.
;;
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;; THE SOFTWARE.


(define anbt-proc-for-all-layers:proc-list
  '(
    ("不透明度を100に"
     . (lambda (img layer) (gimp-layer-set-opacity layer 100)))
    ("階調の反転"
     . (lambda (img layer) (gimp-invert layer)))
    ("アルファチャンネルを削除"
     . (lambda (img layer) (gimp-layer-flatten layer)))
    ("レイヤーモードを「乗算」に"
     . (lambda (img layer) (gimp-layer-set-mode layer MULTIPLY-MODE)))
    ("レイヤーをキャンバスに合わせる"
     . (lambda (img layer) (gimp-layer-resize-to-image-size layer)))
    ))


(define (script-fu-anbt-proc-for-all-layers img proc-index)
  (gimp-image-undo-group-start img)

  (let ((layer-id-list
         (vector->list (cadr (gimp-image-get-layers img))))
        (proc
         (eval (cdr (nth
                     proc-index
                     anbt-proc-for-all-layers:proc-list)))))

    (for-each
     (lambda (layer) (proc img layer))
     layer-id-list))
  
  (gimp-displays-flush)
  (gimp-image-undo-group-end img))


(script-fu-register
 "script-fu-anbt-proc-for-all-layers"
 "<Image>/Filters/すべてのレイヤーに対して処理"
 "すべてのレイヤーに対して処理"
 "sonota"
 "(c) 2010"
 "2010-08-30"
 "RGB*, GRAY*, INDEXED*"
 SF-IMAGE "Image" 0
 SF-OPTION "処理" (map car anbt-proc-for-all-layers:proc-list))

Gimp関連記事のもくじ

Script-Fu: 「すべてのレイヤーに対して処理○○を行う」のテンプレートとスクリプト作成メモ

割と使いどころが多そうなのでテンプレート的に用意しておきたいというのと、 せっかくなので手順を簡単にメモりました。

例として、それぞれのレイヤーに対して 「階調を反転」を適用するスクリプトを書いてみます。


ポイントはこんなところ:

作業用メモ

まずは Script-Fuコンソール や script-fu-shell.rb などを使って関数の挙動などをチェックしていきます。

;; 「レイヤー番号のリスト」の取得には gimp-image-get-layers が使えそう
> (define img 3) ;; 作業用なので適宜 defnie で束縛(代入)しちゃって良いと思います
img
> (gimp-image-get-layers img)
(3 #( 30 29 27 ))
> (cadr (gimp-image-get-layers img))
#( 30 29 27 ) ;=> 上のレイヤーが先
> (vector? (cadr (gimp-image-get-layers img)))
#t

;; ベクトルには for-each が使えないようなのでリストに変換
> (vector->list (cadr (gimp-image-get-layers img)))
(30 29 27)

;; 変数 layer-id-list に束縛
> (define layer-id-list (vector->list (cadr (gimp-image-get-layers img))))
layer-id-list

> (for-each (lambda (drw) (gimp-message (number->string drw))) layer-id-list)
((#t) (#t)) ;=> 上のレイヤーから順に、エラーコンソールにレイヤー番号が表示される

;; 上のレイヤーから順番にレイヤー番号を参照できていることが確認できたので
;; それぞれに対して階調の反転を適用してみる
> (for-each (lambda (drw) (gimp-invert drw)) layer-id-list)
((#t) (#t)) ;=> すべてのレイヤーに対して階調の反転が適用できた

for-each の部分は Ruby 風に書くとこんな感じですね:
layer_id_list.each{|drw| gimp_invert(drw) }

まとめて書き直す

だいたいこんな風にやればできるな、ということが分かったので 関数の形にまとめてみます。


;; layer-id-list もなくせるが、読みやすさのため残してみた
(define (invert-all-layers img)
  (let ((layer-id-list (vector->list (cadr (gimp-image-get-layers img)))))
    (for-each
     (lambda (drw) (gimp-invert drw))
     layer-id-list)))

(invert-all-layers 3) などと呼び出して、ちゃんと動くか確認。

仕上げ

あとは Script-Fu のテンプレートにはめ込んでやれば完成です。


(define (script-fu-invert-all-layers img)
  (let ((layer-id-list (vector->list (cadr (gimp-image-get-layers img)))))
    (gimp-image-undo-group-start img)   ; アンドゥしたらここに戻る
    (for-each
     (lambda (drw) (gimp-invert drw))
     layer-id-list)
    (gimp-image-undo-group-end img)     ; ここまでがアンドゥの対象
    (gimp-displays-flush)))

(script-fu-register
 "script-fu-invert-all-layers"
 "<Image>/Script-Fu/misc/すべてのレイヤーに「階調の反転」" ; このスクリプトのメニュー位置
 "すべてのレイヤーに「階調の反転」"        ; このスクリプトの説明
 "sonota"            ; 作者名
 "(c) 2010"          ; コピーライト
 "2010-07-24"        ; 日付
 "RGB*, GRAY*"       ; スクリプトが動作可能なモード
 SF-IMAGE "Image" 0  ; 引数1
 )

というわけで、あとは (gimp-invert drw) の部分を書き換えれば、 各レイヤーに対してあんなことやこんなことができるようになります :)

たとえば
(gimp-image-raise-layer-to-top img drw)
とするとレイヤーを逆順に並べ換えることができます (GIFアニメの逆まわしなんかもこれでできます)。

20100725 追記: これに関してはメニューの [ レイヤー>重なり>レイヤー順序の反転 ] でできることが分かりました。

わざわざ ~.scm にしてメニューから呼び出さなくても、 次のコードをエディタでいじりつつ Script-Fuコンソールに貼って使う というのも良いと思います。


;; IMG_ID と foo-proc を適宜書き換えるなどして使う
(define img IMG_ID)
(for-each
 (lambda (drw) (foo-proc drw))
 (vector->list (cadr (gimp-image-get-layers img))))))

関連記事


Gimpに関する記事のもくじ

Emacs で Script-Fu を書いて実行させる / script-fu-shell.rb

環境: Ubuntu Studio 9.04 / Gimp 2.6.6 / Ruby 1.8.7 / Emacs 23.0.91.1

ダウンロード

ここからダウンロードして適当なところに置いてください。
http://github.com/sonota/script-fu-shell/blob/master/script-fu-shell.rb
sonota's script-fu-shell at master - GitHub

script-fu-shell.rb を単体で動かしてみる

Gimp を起動し、メニューから [フィルタ > Script-Fu > サーバスタート]
(Gimp のバージョンによってメニュー位置が違います)

「サーバスタート」をクリックしてサーバを開始させます。

端末で
$ ruby script-fu-shell.rb
と実行するとプロンプトが表示され、 Gimp本体の Script-Fu コンソールを使うのと同じ要領で S式を書くと 対話的に実行されます。

たとえばプロンプトに続けて
(gimp-display-new (car (gimp-image-new 640 480 0)))
と入力しエンターキーを押すと、Gimp側で新規画像が表示されます。

Emacs から使う

手軽に試してみる

Emacs には最初から cmuscheme という Scheme用の便利なライブラリが付属しており、 これをそのまま利用することができます。

まず手軽に試してみたいという場合は scratch バッファで
(setq scheme-program-name "~/test/script-fu-shell.rb")
などと書いて C-xC-e で評価し「Scheme インタプリタとして script-fu-shell.rb を使う」ように設定します。

次に M-x run-scheme すると、Script-Fu用のバッファが開きプロンプトが表示されます。 適当に S式を入力して試してみてください。

プロンプトの位置にカーソルを置いて M-p, M-n で履歴を前後に辿れます。

Script-Fu メモ

メモ。

コーディング

新旧の違いなど

2.2 以前の Script-Fu: SIODベース。
2.4 以後の Script-Fu: TinySchemeベース。Tiny-Fu。

関数について調べる場合


概ねこの図のような関係になっているので、

  • Gimp に固有の関数についてはプロシージャブラウザで調べる
  • TinyScheme の部分については「TinyScheme」「Scheme」 などのキーワードと関数名や機能名を組み合わせて検索する

という感じになります。

追記 20091126:
Gimp 公式サイトの Script-Fu Migration Guide というページに
More information about the Scheme syntax of Script-Fu can be found in the Revised5 Report on the Algorithmic Language Scheme, also know as R5RS. Tinyscheme does not support all features of R5RS, but if a precedure is available, it is supposed to behave like documented.
という記述があり、 訳すと「Script-Fu の Scheme の文法についてもっと知りたい場合は R5RS として知られている Revised5 Report on the Algorithmic Language Scheme を参照してください。 TinyScheme は R5RS のすべての機能をサポートしている訳ではありませんが、 procedure が使える場合はこの文書に説明されているように動くはずです。」 といった感じです。
なので、TinyScheme の文法や関数について原典に当たりたい場合はここ http://schemers.org/Documents/Standards/R5RS/HTML/ を見れば良いようです(ただし英語ですが)。

ある関数が Script-Fu で使えるかどうか調べる

Script-Fu コンソールに関数名だけ入力して評価(実行)

> number->string
#<CLOSURE> ←使える
> number2string
Error: eval: unbound variable: number2string ←使えない(number2stringは束縛されていない=定義されていない)

エラーコンソールと gimp-message

printfデバッグの Script-fu 版。

メニュー > ウィンドウ > ドッキング可能なダイアログ > エラーコンソール
でエラーコンソールを開いておく。

Script-Fu 側で gimp-message 関数に文字列を渡す。

gimp-message-error-console

tracing

メッセージが大量に出て??とりますが何もないよりは助かります。


> (tracing 1) ←トレースを有効にする

Gives: 0
> (number->string "foo") ←エラーの起こる S式

Eval: (number->string "foo")
Eval: number->string
Eval: "foo"
Apply to: ("foo")
Eval: (anyatom->string n number?)
Eval: anyatom->string
Eval: n
Eval: number?
Apply to: ("foo" #)
Eval: (if (pred n) (atom->string n) (error "xxx->string: not a xxx" n))
Eval: (pred n)
Eval: pred
Eval: n
Apply to: ("foo")
Eval: (error "xxx->string: not a xxx" n)
Eval: error
Eval: "xxx->string: not a xxx"
Eval: n
Apply to: ("xxx->string: not a xxx" "foo")Error: xxx->string: not a xxx "foo" 

参考: Gimp wiki - ScriptFuClass/Staying > スクリプトのデバッグ方法

エディタ

Emacs を使うと Scheme コーディング用の支援機能がいろいろと使えて理想的なのですが、 多少操作が独特なのでとっつきにくいかもしれません。 括弧が多い言語なので、Emacs 以外を使う場合でも、 サクラエディタなど対応する括弧のハイライト機能があるエディタを選んで使うと作業しやすいと思います。

gimp-shell.el

SIODベースの Script-Fu 用に書かれているためかそのままでは動きませんが、 Emacs ユーザの方は一度試しみてはいかがでしょうか。

Script-Fu: 任意のタイミングで自動で連番ファイル名を決定して保存

本をスキャンし、連番を付けて保存したい。 ScanSnap みたいなスキャナが必要なほど大量ではないが、 十数枚程度でも「ファイル名を付けて保存」する工程が非常にだるい。 連番の次の番号を確認するのが面倒だし、ファイル名をタイプするのも面倒、毎回拡張子を手打ちするのも不毛。 ものすごくだるい。

という訳でショートカットキー一発であらかじめ指定したフォルダに連番で保存するための Script-Fu を書いてみました。 保存した後画像を閉じるとこまでできれば良かったんですが、 gimp-display-delete が使えないようだったのでそこは手動になります。

あとは保存フォルダ・桁数・増分値を変更しようと思ったら スクリプトを開いて修正しないといけないのがいけてませんが、ここも我慢です。 保存フォルダと桁数に関しては、自分で使う分には保存フォルダ固定で問題なく、 増分値は手軽に変更できると良いのですが今後の課題ということで。

使い方・手順

作業開始時に

  • 必要ならスクリプトを開き作業用フォルダのパスと桁数、連番の増分値を修正
  • 必要なら保存フォルダの next-number.txt を開き、次に保存するファイルの番号を入力して保存

しておき、あとは以下の手順を繰り返す。

  • 画像をスキャン(または画像を修正するなど)
  • 通常の Script-Fu と同様に使う。ショートカットキーを割り当てておくと吉。
  • (Ctrl+W で画像を閉じる)

番号を間違えて保存するなど、ミスったときは next-number.txt の番号を修正してやり直す。

スクリプト


;; anbt-continuous-save.scm

;; The MIT License

;; Copyright (c) 2009 sonota

;; Permission is hereby granted, free of charge, to any person obtaining a copy
;; of this software and associated documentation files (the "Software"), to deal
;; in the Software without restriction, including without limitation the rights
;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
;; copies of the Software, and to permit persons to whom the Software is
;; furnished to do so, subject to the following conditions:

;; The above copyright notice and this permission notice shall be included in
;; all copies or substantial portions of the Software.

;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
;; THE SOFTWARE.


(define (script-fu-anbt-continuous-save img drw)
  (let*
	  ((fr nil)
	   (fw nil)
	   (digits 4) ; 桁数
	   (step 1) ; 増分値
	   (work-dir "/home/USER/gimp-continuous-save-temp/") ; 作業用フォルダ
	   (next-number-file (string-append work-dir "next-number.txt")) ; 番号保存用ファイル名
	   (next-number nil)
	   (save-file-name nil))

	;; 桁数と数を指定して整形
	;; 000xx
	;; ----- digits
	;; ---   zero-length
	;;    -- n-length
	(define (zero-padding-number digits n)
	  (let*
		  ((n-str (number->string n))
		   (n-length (string-length n-str))
		   (zeros-str "")
		   (zero-length (- digits n-length))
		   (i 0))
		
		(while (< i zero-length)
			   (set! zeros-str (string-append zeros-str "0"))
			   (set! i (+ i 1)))
		(string-append zeros-str n-str)))

	;; アンドゥしたらここに戻る
	(gimp-image-undo-group-start img)
	
	;; ファイルから番号読み込み
	(set! fr (open-input-file next-number-file))
	(set! next-number (read fr))

	;; ファイル名生成
	(set! save-file-name (string-append work-dir (zero-padding-number digits next-number) ".jpg"))

	;; 画像にファイル名をセット
	(gimp-image-set-filename img save-file-name)

	;; 必要ならここに処理を適宜追加する
	;; ここでは例として画像を右90度回転
	(gimp-image-rotate img ROTATE-90)

	;; 保存
	(file-jpeg-save 1 ; 保存ダイアログを開かない
					img drw
					save-file-name
					save-file-name ; raw-filename
					0.95
					0 ; smoothing
					1 ; optimize
					0 ; progressive
					"" ; comment
					0 ; subsmp
					0 ; baseline
					0 ; restart
					0 ; dct
					)
	
	;; 増分値を加算
	(set! next-number (+ step next-number))

	;; ファイルに番号書き込み
	(set! fw (open-output-file next-number-file))
	(display next-number fw)

	;; 「修正なし」状態にする
	;; (画像を閉じる時にダイアログを出さないようにするため)
	(gimp-image-clean-all img) 

	;; ここまでがアンドゥの対象
	(gimp-image-undo-group-end img)))


(script-fu-register
  "script-fu-anbt-continuous-save"
  "<Image>/Script-Fu/misc/連番で保存" ; このスクリプトのメニュー位置
  "連番で保存" ; このスクリプトの説明
  "sonota" ; 作者名
  "(c) 2009" ; コピーライト
  "2009-10-11" ; 日付
  "RGB*, GRAY*, INDEXED*"  ; スクリプトが動作可能なモード
  SF-IMAGE "Image" 0       ; 引数1
  SF-DRAWABLE "Drawable" 0 ; 引数2
)

その他

桁数と数を指定して整形する関数 zero-padding-number は □置きざり保管庫: GIMPをscript-fuで自動化(2008-07-22) を参考にさせてもらいました。ありがとうございます。

次のように動作します。

> (zero-padding-number 4 12)
"0012"
> (zero-padding-number 16 12)
"0000000000000012"
> (zero-padding-number 1 12)
"12"

Gimpに関する記事のもくじ



** ホームに戻る

<< 前のページ | 次のページ >>