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

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

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 ユーザの方は一度試しみてはいかがでしょうか。

gimp-shell.el / gimp-mode を使ってみた

てきとーメモ。

gimp-shell.el

環境: Ubuntu Studio 8.04 / Gimp 2.4.5 / Emacs 23.0.60.1

そのままでは動かなかったので、 以下の箇所を修正。


;; 修正前
  (gimp-send-string 
   "(define (int--emacs-tostring item)
      (cond ((number? item) (number->string item 10))
 	((string? item) (print-to-string item (string-append (substring item 0)
                                                             \"                                 \" )))
 	((null? item)   \"()\")
        ((eq? t item)    \"t\")
 	((pair? item) 
 	 (string-append \"(\" 
		(unbreakupstr 
 			 (map int--emacs-tostring item) \" \") \")\"))
        (TRUE item)))")

;; 修正後
  (gimp-send-string 
    "(define (int--emacs-tostring item)
      (cond
        ((number? item) (number->string item 10))
        ((string? item) item)
        ((null? item) \"()\")
        ((eq? #t item) \"#t\")
        ((pair? item) 
          (string-append
            \"(\" 
       	    (unbreakupstr 
       	      (map int--emacs-tostring item) \" \")
            \")\"))
        (TRUE item)))")

「とりあえず動く」ようにしただけなので、 もっといいやり方があるはず……。

あとは send-last-sexp、send-definition があるだけでも違うので以下を適当に追加:


;; この2つの関数は cmuscheme から。ほぼそのまま。
(defun gimp-send-last-sexp ()
  "Send the previous sexp to the Script-Fu process."
  (interactive)
  (gimp-send-region (save-excursion (backward-sexp) (point)) (point)))

(defun gimp-send-definition ()
  "Send the current definition to the Script-Fu process."
  (interactive)
  (save-excursion
   (end-of-defun)
   (let ((end (point)))
     (beginning-of-defun)
     (gimp-send-region (point) end))))

...

;; キーバインド
(define-key gimp-mode-map "\C-c\C-r" 'gimp-send-region)
(define-key gimp-mode-map "\C-c\C-e" 'gimp-send-definition)
(define-key gimp-mode-map "\C-x\C-e" 'gimp-send-last-sexp)



** ホームに戻る

<< 前のページ | 次のページ >>
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。