Windows版GIMP-2.10でPython-Fuを試す。

python コンピュータ

GIMPに組み込まれているPython-Fu(Python)を試してみたました。

スポンサーリンク

Pythonのバージョン

2.7.17
現行のPythonのバージョンは3系ですので若干古いです。

対話式スクリプト実行コンソールの起動

メニュー→「フィルター(R)」→「Python-Fu」→「コンソール(C)」
表示されるコンソールにスクリプトを直接記述(コピペ)すると最終行で「…」と表示されますので、さらにエンターキーを押すとスクリプトが実行されます。

一括処理スクリプト

pngファイルをGMIPの標準ファイル形式であるxcfに一括変換します。

対話式コンソールにコピー&ペーストで実行



import os, glob
path = "H:\\python-fu\\png"
outdir = os.path.join(path, "output")
if not os.path.exists(outdir):
    os.mkdir(outdir)

for src_file in glob.glob(os.path.join(path, "*.png")):
    img = pdb.gimp_file_load(src_file, src_file)
    disp = pdb.gimp_display_new(img)
    dst_file = os.path.join(outdir, (os.path.splitext(os.path.basename(src_file))[0]+'.xcf'))
    pdb.gimp_file_save(img, img.active_layer, dst_file, dst_file)
    pdb.gimp_display_delete(disp)

pngファイルを読み込んで拡張子をxcfに変更して保存しているだけに見えますが、これで画像フォーマットの変換がされているようです。

フィルター用プラグイン(.pyスクリプト)の保存場所

メニュー→「編集(E)」→「設定(P)」→「フォルダー」→「プラグイン」
デフォルトでは以下のディレクトリ

%Userprofile%\AppData\Roaming\GIMP\2.10\plug-ins

こちらにフィルタスクリプトを保存する

選択範囲の隣の範囲をコピーするフィルタスクリプト

# coding: utf8

#!/usr/bin/env python

from gimpfu import *
from array import array

def get_offset(x1, y1, x2, y2, width, height):
	
	sw = x2 - x1 + 1
	sh = y2 - y1 + 1
	
	offset_x = 0
	offset_y = 0
	
	if ((sw > sh) and (y1 - sh) > 0 and (y2 - sh) > 0):
		# Up
		offset_y = sh * -1
	elif ((sw > sh) and (y1 + sh) <= height and (y2 + sh) <= height):
		# Down
		offset_y = sh
	elif ((x1 - sw) > 0 and (x2 - sw) > 0):
		# Left
		offset_x = sw * -1
	elif ((x1 + sw) <= width and (x2 + sw) <= width):
		# Rihgt
		offset_x = sw
	
	
	return (offset_x, offset_y)



def plugin_main(image, layer):
    w = layer.width
    h = layer.height
    
    # gimp.message("A")
    
    (non_empty,x1,y1,x2,y2) = pdb.gimp_selection_bounds(image)
    
    if (non_empty == 0):
        return
    
    # gimp.message("B")
    
    offset_x = 0
    offset_y = 0
    
    (offset_x, offset_y) = get_offset(x1, y1, x2, y2, w, h)
    
    
    dst_rgn = layer.get_pixel_rgn(0, 0, w, h, False, True)
    src_rgn = layer.get_pixel_rgn(0, 0, w, h, False, False)
    
    # gimp.message("C")
    
    for i in range(x1,x2):
        for j in range(y1, y2):
            r = pdb.gimp_selection_value(image, i, j)
            if (r != 0):
                
                
                # gimp.message("V")
                p = map(ord, src_rgn[i+offset_x, j+offset_y])
                red = p[0]
                green = p[1]
                blue = p[2]
                alpha = p[3]
                dst_rgn[i, j] = array("B", [red, green, blue, alpha]).tostring()
                
    # gimp.message("S")
    
    layer.flush()
    layer.merge_shadow()
    layer.update(0,0,w,h)


register("mycpla", "", "", "", "", "",
    "mycpla", 
    "RGB*",
    [
    (PF_IMAGE, "image", "Input image", None),
    (PF_DRAWABLE, "drawable", "Drawable", None)
    ],
    [],
    plugin_main,
    menu = "<Image>/Filters")

main()

ファイル名をmycpla.pyでプラグインディレクトリに保存し、GMIPを再起動するとメニュー→「フィルター(R)」の下の方にmycplaが追加されます。失敗すると追加されないわけですが、エラーも表示されません。以下のデバック用コンソールを駆使して調査することになります。

フィルタの機能は範囲選択した状態で実行すると選択範囲の上部又は左側のピクセルを選択範囲にコピーするスクリプトになります。
ピクセルを一点一点読み込んでは貼り付ける作業をしていますので非常に時間がかかります。コピースタンプ機能を自動化しようと思いましたが、自分のプログラミング能力ではこの辺りが限界でした。

選択範囲で切り取り新規レイヤーにコピー

# coding: utf8

#!/usr/bin/env python

from gimpfu import *
from array import array

# 選択範囲で切り取り新規レイヤーにコピー

def plugin_main(image, layer):
    pdb.gimp_layer_add_alpha(layer)

    w = layer.width
    h = layer.height
    
    # gimp.message("A")
    
    (non_empty,x1,y1,x2,y2) = pdb.gimp_selection_bounds(image)
    
    # 選択範囲がない場合終了
    if (non_empty == 0):
        return
    
    # gimp.message("B")
    
    
    # 新しいレイヤーの追加
    name = "new"
    width   = image.width
    height  = image.height
    type    = RGB_IMAGE
    opacity = 100
    mode    = NORMAL_MODE
    new_layer = gimp.Layer(image, name, width, height, type, opacity, mode)

    # 最前列にレイヤーを追加
    position = 0
    image.add_layer(new_layer, position)

    # アルファチャンネルの追加
    pdb.gimp_layer_add_alpha(new_layer)
    pdb.gimp_edit_clear(new_layer)
    
    # 透明色で塗りつぶす
    new_layer.fill(TRANSPARENT_FILL)
    
    # 選択範囲を切り取り
    pdb.gimp_edit_cut(layer)
    
    # 新しいレイヤーに貼り付け
    floating_sel = pdb.gimp_edit_paste(new_layer, 0)
    # 貼り付けを固定
    pdb.gimp_floating_sel_anchor(floating_sel)
    
    # 元レイヤーをアクティブに
    pdb.gimp_image_set_active_layer(image, layer)
    
register("CutToNewLayer", "", "", "", "", "",
    "CutToNewLayer", 
    "RGB*",
    [
    (PF_IMAGE, "image", "Input image", None),
    (PF_DRAWABLE, "drawable", "Drawable", None)
    ],
    [],
    plugin_main,
    menu = "<Image>/Filters")

main()

範囲選択した状態で実行すると、レイヤーが新規に追加され、選択範囲が元レイヤーから切り取られ、新しいレイヤーに貼り付けられます。

デバック用にコンソールを表示させる起動オプション

gimp-2.10.exe --console-messages

私は起動用のショートカットにオプションを設定して使っています。

gmip.message("文字列")

で文字列がコンソールに出力されます。

現在のイメージとアクティブレイヤーの取得

# 現在のイメージを取得
image = gimp.image_list()[0]

# アクティブレイヤー
layer = image.active_layer

画像を範囲選択した後フィルターを実行すると、新しいレイヤーが追加され選択された範囲が、元のレイヤーから切り取られ新しいレイヤーに貼り付けます。

最後に

Python-Fuは多機能なGIMPに組み込まれたマクロ的な代物なので、魅力的だと思うのですが意外と日本語の情報が少なくて残念です。
個人的にはOpenCVあたりと組み合わせると楽しいことが出来そうだと思ったのですが、私にはちょっと難しそうです。
開発環境、特にフィルタを作って試す為に何度もGIMPの起動と終了を繰り返すことになり中々大変です。まず自分の環境できちんと動作するフィルタ登録部分の雛形スクリプトを用意するところから始めると良さそうです。

コメント