省型旧形国電の残影を求めて

戦前型旧形国電および鉄道と変褪色フィルム写真を中心とした写真補正編集の話題を扱います。他のサイトでは得られない、筆者独自開発の写真補正ツールや補正技法についても情報提供しています。写真補正技法への質問はコメント欄へどうぞ

GIMP / Python 自作プラグイン解説: ファイルをマスクとして読込む

 先日アップデートした画像ファイルをレイヤーマスクとして読み込むプラグインですが...

yasuo-ssi.hatenablog.com GIMP / Python プログラミングは結構難しいので、今回、GIMP / Pythonプログラマーの方に参考になるように、コードの解説をつけます。

---------------

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 以上UTF-8を有効にしたPythonプログラムという宣言

# Plug-in:      Open file as mask
# Version:      0.12
# Date:         2022_07_25

# (以下コメント略)

from gimpfu import *
import os, glob

# 以上読込むライブラリーの宣言

def import_file_as_mask(img, drawable, filename):

# 実質的なメイン部分の宣言
# 引数は、
  img: 現在アクティブなimageオブジェクト
  drawable: 現在アクティブな drawable (レイヤー or マスク)
  filename: ファイル名


    pdb.gimp_message_get_handler(ERROR_CONSOLE)
# メッセージはエラーコンソールに出力する指定

    ismask = pdb.gimp_item_is_layer_mask(drawable)
# drawableがマスクかどうかを調べる
    if ismask == TRUE: # もし drawable がマスクなら
        layer_active = pdb.gimp_layer_from_mask(drawable)
        #  マスクの属するレイヤーを取得
        drawable = layer_active
        # レイヤーを drawableに代入
  # これで drawable は以下レイヤーに統一

    pdb.gimp_image_undo_group_start(img)
# 取り消す場合の範囲ここから始まる

    try:
        imgload = pdb.gimp_file_load(filename, filename)
# filenameで指定したファイルをimgloadに読み込む
        disp = pdb.gimp_display_new(imgload)
# imgloadの画像を新しいファイルとして表示する
    except Exception, error:
        print error
    pdb.gimp_edit_copy(imgload.layers[0])
# 読んだ画像の最初のレイヤーをコピーする
    if pdb.gimp_drawable_has_alpha (drawable) == FALSE:
# もしマスクをつけたいレイヤーにαチャンネルがなければ
        pdb.gimp_layer_add_alpha (drawable)
# αチャンネルを追加する
    maskexist = pdb.gimp_layer_get_mask(drawable)
# マスクをつけたいレイヤーのマスクの有無をmaskexit変数に保存
#    gimp.message(str(drawable))
# デバッグ用のメッセージ表示 (現在コメントアウト)
    try:
        mask = pdb.gimp_layer_create_mask(drawable, ADD_WHITE_MASK)
# 地が白のマスク画像をマスクをつけるレイヤーに追加
        if mask != None:
#  マスク画像ができていれば...
            pdb.gimp_layer_add_mask(drawable, mask)
#  マスク画像をレイヤーにマスクとして追加
# 注意! gimp_layer_create_mask だけではまだレイヤーにマスクとして追加されない!!

    except Exception, error:
        print error
# 既にマスクがあればエラーメッセージを表示してマスク付加をスキップ
    pdb.gimp_layer_set_edit_mask(drawable, TRUE) # Activate Mask Edit Mode
# 今つけた(アクティブな)マスクを編集モードにする
    floating_sel = pdb.gimp_edit_paste(drawable.mask, False)
# クリップボードのイメージをフローティング選択範囲としてマスクに貼り付け
    pdb.gimp_floating_sel_anchor(floating_sel)
# フローティング選択範囲をマスクに固定
    pdb.gimp_layer_set_edit_mask(drawable, FALSE)
# マスク編集モードをオフ
    pdb.gimp_display_delete(disp)
# 読み込んだ画像の表示を削除
    pdb.gimp_image_undo_group_end(img)
# 取り消す場合の範囲ここまで
    return

register(
    "Open_file_as_mask",
    "Open file as mask",
    "ファイルをマスクとして読込む",
    "Ohnishi, Yasuo",
    "Ohnishi, Yasuo",
    "2021-22 Ver 0.12",
    "マスクとして読込む...",
    "*",      # Alternately use RGB, RGB*, GRAY*, INDEXED etc.
    [
#   現在アクティブな image と drawable を "img" と "drawable" として読込む
# また読み込む画像ファイル名をダイアログから指定する

    (PF_IMAGE, "img", "Input image", None),
    (PF_DRAWABLE, "drawable", "Input drawable", None), 
    (PF_FILENAME, "filename", "入力ファイル名", ""),
    ],
    [],
    import_file_as_mask, menu="<Image>/File/Open" )
main()

---------------

 なお、2021年6月のアップデートで、複数のファイルが読み込まれていると、指定したファイルのレイヤーではなく、最後に読み込んだファイル (image オブジェクト) のアクティブなレイヤーに対しマスクがかかってしまうという現象を直せなかったのは、指定したアクティブなレイヤーを読み込むのに gimp-image-get-active-layer API を使ってたためのようです。
 本来ならこれで問題ないはずなのですが、複数のファイルを読み込んだ状態で、途中で他のファイルを読み込んだり複雑な操作を行ったりして、一時的にアクティブな imageオブジェクトが移ると、最終的にアクティブな image オブジェクトが最後に読み込んだ image になってしまうようです。その際、gimp-image-get-active-layer API で読み込んでおいた drawable (レイヤー) も予め指定しておいた image の drawable ではなく、その時点でアクティブな image のアクティブな drawable に移ってしまうようです。つまり、gimp-image-get-active-layer API で読み込んでおいたポインタは、どうやら常にその時点でアクティブな image のアクティブな drawable を示すようです。これが仕様なのか、それとも複雑な操作をやったときのみ発生するバグなのかは、まだ追求できていません。これを、drawable が他のものに入れ替わらないようにするには、APIでdrawableを読まずに、Registerから drawable を読み込んでおく必要があるようです。
 改訂した本プラグインでも、コードに一切指定していないにもかかわらず、実行後は、なぜか最終的にアクティブな image が最後に読み込んだ image になってしまいます。なお、プロシジャーブラウザで調べられる GIMPAPIの中には、現在アクティブなimageを設定するAPIは存在しません。