GIMP2.10でScript-Fuを試してみる2。「選択範囲を別レイヤーに切り出す」

GIMP コンピュータ
GIMP
GIMPのPythonで作ったプラグインスクリプトをc言語で書き直す方法を模索してみました。
これはこれで面白そうなので、いつか取り組もうとは思うのですが、取り急ぎScript-Fuで書き直すことを考えたいと思います。
自分の使うスクリプトは条件分岐やループがほとんどない、関数をただ並べたような代物が多いので比較的簡単に移植出来るのではと楽観的に考えています。

スクリプト言語自体に慣れていないのでコンソールで1行1行関数を実行して確認しながら進めてみたいと思います。
それでは、選択範囲を別レイヤーに切り出すスクリプトを移植するために各関数の確認作業を始めます。
Python-Fuで選択範囲を別レイヤーに切り出し
一枚の絵をパーツごとに切り出してレイヤー化する作業用に作成しました。 手動で実行する手順の自動化で、以前にも同じ目的のスクリプトを作りましたが別手順になります。 #!/usr/bin/env python # coding: utf8 fr...

選択範囲の座標を取得

pythonでは関数名の単語はアンダーバー(_)で区切られていましたがScript-Fuではハイフン(-)で区切られています。

> (define img (aref (car (cdr (gimp-image-list))) 0))
img
> (define layer(car (gimp-image-get-active-layer img)))
layer
> (gimp-edit-fill layer 0)
(#t)
> (gimp-selection-bounds img)
(1 147 102 260 207)

まず、gimp-selection-boundsを実行するため引数となるimageオブジェクトが必要となります。
コンソールで実行するために事前に処理を実行します。
define img…とdefine layer…は現在開かれているimageオブジェクトとlayerオブジェクトを取得しています。
gimp-edit-fill layerは前景色で塗りつぶしです。こちらは確認のため実行しています。

続いてgimp-selection-boundsを実行したところ戻り値は
(1 147 102 260 207)
となりました。
1番目は選択範囲の有無で、結果から1がありで0が無しだと思われます。
2番目はx1
3番目がy1
4番目がx2
5番目がy2
の座標がセットされています。
ちなみになげなわ選択で円の様に範囲選択していますが、取得できる座標はx1-x2 y1-y2ですので矩形の情報になります。

このままだと使いづらいので戻り値を変数にセットします。

 (define sb (gimp-selection-bounds img))
sb

選択範囲の有無を変数にセット

code>(define non_empty (car sb))
non_empty

x1を変数にセット

code>(define x1 (car (cdr sb)))
x1

y1を変数にセット

code>(define y1 (car (cdr (cdr sb))))
y1

x2を変数にセット

code>(define x2 (car (cdr (cdr (cdr sb)))))
x2

y2を変数にセット

code>(define y2 (car (cdr (cdr (cdr (cdr sb))))))
y2

もっと良い方法があると思いますが、とりあえずこれで戻り値が各変数に収まりました。

レイヤーにアルファチャンネルを追加

(gimp-layer-add-alpha layer)
(#t)

引数にlayerをセットしています。実行したところアルファチャンネルが追加されていました。

レイヤーの複製

レイヤーのコピーとレイヤーをイメージオブジェクトに挿入(ペースト)になります。
コピー処理

(define new_layer (car (gimp-layer-copy layer 1)))
new_layer

引数1はアルファチャンネルをコピーするフラグ1がTRUE
new_layerはオブジェクトではなく数値のようです。
詳しく理解できていないのですが、car処理を挟まないと次の挿入処理に使う引数で蹴られてしまいました。

挿入処理
python-fuではimageオブジェクトにメソッドでadd_layer()としていましたが、Script-Fuではgimp-image-insert-layer関数を使ってみます。

(gimp-image-insert-layer img new_layer 0 0)
(#t)

レイヤーがコピーされていました。

レイヤーのオフセットを取得

(define of (gimp-drawable-offsets new_layer))
(define x0 (car of))
(define y0 (car (cdr of)))

レイヤーサイズの変更

不要部分を縮小し選択範囲のみを残す処理です。まずレイヤーサイズを縮小します。

(gimp-layer-resize new_layer (- x2 x1) (- y2 y1) (- x0 x1) (- y0 y1))

レイヤーサイズの計算で引き算しているのですがマイナス演算子の位置が先頭になります。
また、各計算も()で括ってあげます。

選択範囲外を透明で塗りつぶし

まず選択範囲を反転します。

(gimp-selection-invert img)

次に透明色で塗りつぶし処理。

(gimp-edit-fill new_layer 3)

元レイヤーの選択部分を切り抜き

反転していた選択範囲をもとに戻します。
処理は同上。

元レイヤーの選択範囲を透明色で塗りつぶし

(gimp-edit-fill layer 3)

元レイヤーをアクティブに変更

(gimp-image-set-active-layer img layer)

スクリプトの登録

一連のフィルタ部分の目途が立ちましたのでスクリプトに仕立てあげたいと思います。
スクリプトの保存場所:%Userprofile%\AppData\Roaming\GIMP\2.10\scripts
ファイル名:cut-new-layer.scm

; 
; 選択範囲をレイヤーに切り出すスクリプト
; 
(define (script-fu-cut-new-layer img layer)
    
    ; Undo記録開始
    (gimp-undo-push-group-start img)
    ; 選択範囲座標の取得
    (define sb (gimp-selection-bounds img))
    (define non_empty (car sb))
    (define x1 (car (cdr sb)))
    (define y1 (car (cdr (cdr sb))))
    (define x2 (car (cdr (cdr (cdr sb)))))
    (define y2 (car (cdr (cdr (cdr (cdr sb))))))
    ; アルファチャンネルを追加
    (gimp-layer-add-alpha layer)
    ; レイヤーの複製
    (define new_layer (car (gimp-layer-copy layer 1)))
    (gimp-image-insert-layer img new_layer 0 0)
    ; オフセット取得
    (define of (gimp-drawable-offsets new_layer))
    (define x0 (car of))
    (define y0 (car (cdr of)))
    ; レイヤーサイズの変更
    (gimp-layer-resize new_layer (- x2 x1) (- y2 y1) (- x0 x1) (- y0 y1))
    ; 選択範囲外を透明で塗りつぶし
    (gimp-selection-invert img)
    (gimp-edit-fill new_layer 3)
    ; 元レイヤーの選択部分を切り抜き
    (gimp-selection-invert img)
    (gimp-edit-fill layer 3)
    ; 元レイヤーをアクティブに変更
    (gimp-image-set-active-layer img layer)
    ; Undo記録終了
    (gimp-undo-push-group-end img)
    (gimp-drawable-update layer 0 0 (car (gimp-drawable-width layer)) (car (gimp-drawable-height layer)))
    (gimp-displays-flush)
)
(script-fu-register "script-fu-cut-new-layer"
                    "<Image>/Filters/My/レイヤー切り出し..."
            "選択範囲をレイヤーに切り出します。"
            "Maywork"
            "Copyright 2020, Maywork"
            "04/06/2022"
            "RGB* GRAY*"
            SF-IMAGE "Input Image" 0
            SF-DRAWABLE "Input Layer" 0
)

実行

GIMPを起動し400x400pxの画像を新規作成。投げ縄選択で丸く選択し前景色(青)で塗りつぶした状態。

メニュー「フィルター」→「My」→「レイヤー切り出し」を実行

画像自体は変化していないようにみえますが、レイヤーが二つに増えています。

選択範囲を切り出したレイヤー

範囲選択された部分が収まる矩形に合わせたレイヤーサイズなっています。
また範囲外は透明になっています。

切り抜かれた元レイヤー

選択範囲分が透明になっています。

以上

コメント