GIMPのスクリプト（python-fu）のつくり方について書くで？🤜🤛

#はじめに
画像編集をする際に毎回同じ操作をすることがあると思います。例えばiPhoneやAndroidのアプリアイコンを作成する場合は様々なサイズのアイコンを作成する必要があります。毎回毎回同じ操作をすると嫌になってきます。

もちろん俺らは抵抗するで？🤜🤛 

今回は画像編集のフリーソフトGIMPのpython-fuを利用してこのような操作を自動化する方法について記載します。

python-fuはGIMPをpythonで作成したスクリプトで自動化する仕組みです。

#開発環境
macOS Sierra　バージョン10.12

GIMP 2.8.18

Python 2.7.10

#準備
GIMPは[ここ](https://www.gimp.org/downloads/)からダンロードできます。

MACの場合はpythonの開発環境はすでに整っています。

エディターは好みのものをどうぞ。今回は[CotEditor](https://coteditor.com)を使用しました。


#スクリプト作成
さっそくスクリプト作成していきます。

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

from gimpfu import *

def plugin_main(image, layer):
    gimp.message("Hello World" )

register(
	"hello_world",#コマンドラインまたはスクリプトから呼び出す場合のコマンドの名前
	"Show hello world",#プラグインの説明
	"Show hello world(detail)",#プラグインの詳細な説明
	"am(author)",#プラグインの作成者
	"am(copyright)",#プラグインの著作権保有者 (通常は author と同じ)
	"2017/12/22",#著作権の日付
	"<Image>/Filters/Languages/Python-Fu/helloworld", #メニューの中でプラグインに使用されるラベル
	"RGB*, GRAY*", #プラグインで処理する対象となる画像のタイプex. RGB*, GRAY* など
	[],#引数(型, 名前（プロシージャブラウザに表示される）,説明, 初期値)
	[], # 戻り値
	plugin_main) # メソッド名

main()
```

上記をコピーしhello.pyと名前をつけて保存します。（保存時に実行権を付与する）

Library/Application Support/GIMP/2.8/plug-insにhello.pyを置きGIMPを起動して適当に画像を開きます。すると、下記のようにフィルター(R)→Python-Fuにhelloworldと表示されます。

GIMP2.10でも自分でplug-insフォルダを作ってそこに配置すると表示されました（2020/01/12追記）

<img width="500" alt="filter1.png" src="https://qiita-image-store.s3.amazonaws.com/0/225999/72e7918f-11ed-dcb0-52f7-27b20490d8a0.png">

これを実行すると「Hello World」というダイアログが表示されます。

上記のスクリプトがPython-fuで利用するのに必要な最低限の実装です。

#Registerについて
スクリプトのregister部分についてもう少し説明します。

上記のスクリプトをGIMPに追加してヘルプ(H)→プロシージャーブラウザー(B)を選択しhelloと検索すると下記のように表示されると思います。
<img width="350" alt="search.png" src="https://qiita-image-store.s3.amazonaws.com/0/225999/d1a77f45-6ae4-9d07-489a-f0310f1ecbe6.png">

registerに記載した情報はここに表示されます。

著作権の日付まではスクリプトのコメントに記載した通りで特に補足はありません。

- ラベル
	```<Image>/Filters/Languages/Python-Fu/helloworld```は追加したスクリプトをメニューのどこに表示するかを指示しています。
```<Image>/Image/Test/helloworld```と変更すると下記のように表示されます。
<img width="500" alt="filter2.png" src="https://qiita-image-store.s3.amazonaws.com/0/225999/1bf4ac31-fc6d-cbb1-f0ec-e00f4d5f6dfb.png">


	自分が使いやすい位置に表示されるようにしましょう。

- 対象画像タイプ

	スクリプトの対象となる画像タイプ（RGB\*, GRAY\*など）を記載します。例えばRGB\*のみにするとグレースケール画像を開いている場合はスクリプトは実行できないようになります。
	
	常にRGB\*, GRAY\*で問題ないと思います。

- 引数

	引数の種類については[GIMP Python Documentation](https://www.gimp.org/docs/python/#plugin_framework)に詳しく記載されています。
	試しに下記のように引数の部分を書き換えると

	```
[
	(PF_INT8, "PF_INT8", "PF_INT8です", 1),
	(PF_INT16, "PF_INT16", "PF_INT16です", 2),
	(PF_INT32, "PF_INT32", "PF_INT32です", 3),
	(PF_INT, "PF_INT", "PF_INTです", 4),
	(PF_FLOAT, "PF_FLOAT", "PF_FLOATです", 5.0),
	(PF_STRING, "PF_STRING", "PF_STRINGです", "string"),
	(PF_VALUE, "PF_VALUE", "PF_VALUEです", 6),
	(PF_COLOR, "PF_COLOR", "PF_COLORです", (0.0, 0.0, 0.0)),
	(PF_COLOUR, "PF_COLOUR", "PF_COLOURです", (0.5, 0.5, 0.5)),
	(PF_TOGGLE, "PF_TOGGLE", "PF_TOGGLEです", False),
	(PF_BOOL, "PF_BOOL", "PF_BOOLです", True),
	(PF_RADIO, "PF_RADIO", "PF_RADIOです", "A", (("A", "AAA"), ("B", "BBB"), ("C", "CCC"))),
	(PF_SLIDER, "PF_SLIDER", "PF_SLIDERです", 0, (0, 100, 10)),
	(PF_SPINNER, "PF_SPINNER", "PF_SPINNERです", 50, (50, 1000, 50)),
	(PF_ADJUSTMENT, "PF_ADJUSTMENT", "PF_ADJUSTMENTです", 100, (100, 1500, 100)),
	(PF_FONT, "PF_FONT", "PF_FONTです", "Hiragino Maru Gothic ProN"),
	(PF_FILE, "PF_FILE", "PF_FILEです", ""),
	(PF_DIRNAME, "PF_DIRNAME", "PF_DIRNAMEです", ""),
	(PF_BRUSH, "PF_BRUSH", "PF_BRUSHです", "Pencil 01", 100, 5, 0),
	(PF_PATTERN, "PF_PATTERN", "PF_PATTERNです", "3D Green"),
	(PF_GRADIENT, "PF_GRADIENT", "PF_GRADIENTです", "Golden"),
	(PF_PALETTE, "PF_PALETTE", "PF_PALETTEです", "Bgold"),
	]
```

	スクリプト実行時に下記のようなダイアログが表示されます。
	<img width="130" alt="daialog.png" src="https://qiita-image-store.s3.amazonaws.com/0/225999/8f8639e5-a4ed-8a30-d621-08200449d36c.png">


	基本的には(型, 名前, 説明, 初期値)の形式でPF_SLIDER、PF_SPINNER、PF_ADJUSTMENTは他に(最小値、最大値、ステップ数)が必要です。他にもPF_REGIONなど色々引数があるようですが書き方がわかりませんでした...

	ダイアログで設定した引数を受け取るにはスクリプトの```def plugin_main(image, layer):```の引数に追加する必要があります。

	例えばPF_STRINGを引数に追加する場合は```def plugin_main(image, layer, text):```などと変更します。

	```def plugin_main(image, layer):```の引数のimage,layerは必須なので消さないよう気をつけましょう。

#GIMPの関数

GIMPのスクリプトで呼び出す関数にはgimp.~、pdb.~で呼び出す２種類があります。

- gimp.~

	レイヤを作成するなどの基本的な操作の場合はこちらを使用します。
	例えば、レイヤを作成する場合は下記のようになります。
	```layer = gimp.Layer(image, "レイヤ名", width, height, RGB_IMAGE, opacity, NORMAL_MODE)```
	
	どのような関数があるかは[GIMP Python Documentation](https://www.gimp.org/docs/python/#gimp_module_procedures)に一覧があります。
	
- pdb.~

	GIMP内部にプラグインの処理を登録しておくプロシージャデータベース（Procedual Database, pdb）というものが存在し、この関数をpdb.~という形で呼び出すことができます。例えば、画像を拡大・縮小したい場合は下記のようになります。

	```pdb.gimp_image_scale(image, width, height)```

	どのようなプロシージャがあるかはGIMPのヘルプ(H)→プロシージャーブラウザー(B)で検索することができます。

#スクリプト例

では実際にスクリプトを作成してみます。

例として様々なサイズに画像をリサイズして指定のフォルダに保存するスクリプトを作ってみます。

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

from gimpfu import *
import os

def plugin_main(image, layer, dir_path):
    if (not type(dir_path) == type("") or not len(dir_path)):
        gimp.message("フォルダを選択して下さい")
        return
               
    #ファイル保存
    save_files(image, layer, dir_path)
    
def save_file(image, layer, dir_path, file_name): 
    file_path = dir_path+"/"+file_name
    #画像を保存
    pdb.file_png_save(image, layer, file_path, file_path, 1.0, 0, 0, 0, 0, 0, 0)

def save_files(image, layer, dir_path): 
    #200*200にリサイズして画像保存
    pdb.gimp_image_scale(image, 200, 200)
    file_name = "icon200.png"
    save_file(image, layer, dir_path, file_name)
    
    #100*100にリサイズして画像保存
    pdb.gimp_image_scale(image, 100, 100)
    file_name = "icon100.png"
    save_file(image, layer, dir_path, file_name)
    
    #50*50にリサイズして画像保存
    pdb.gimp_image_scale(image, 50, 50)
    file_name = "icon50.png"
    save_file(image, layer, dir_path, file_name)
    
register(
    "python_fu_resize_image",
    "Image resize",
    "Create 3 image files",
    "am",
    "am",
    "2017/12/22",
    "<Image>/Filters/Languages/Python-Fu/resizeImage", 
    "RGB*, GRAY*", 
    [
    (PF_DIRNAME, "directory_path", "Save directoryPath", ""),
    ],
    [], 
    plugin_main) 

main()
```

GIMPで画像を開いて上記のスクリプトを実行すると指定のフォルダに200×200、100×100、50×50にリサイズされたicon50.png、icon100.png、icon200.pngというファイルが作成されます。


#メニューに表示されない場合

スクリプトを作成してGIMPに追加してもメニューに表示されない場合があると思います。その場合は下記の項目について確認してみましょう。

1. GIMP起動中にスクリプトを追加

	GIMPを再起動する必要があります。
	
2. 実行権がない

	作成した.pyファイルに実行権がない場合、実行権を付与する必要があります。ターミナルを開いて```chmod +x ファイルパス```を実行し実行権を付与します。
	
3. image,layer引数がない

	```python
	def plugin_main(image, layer):
	    #image,layerは必須
	    #メソッド内に最低一行は必要
	    print "Hello, world!"　
   ```
4. コマンド名が重複している
	
	registerの１行目のコマンド名は重複しないようにする必要があるためユニークな名前をつける必要があります。

5.  構文エラー

- pythonの構文エラー
- インデントがおかしい
- 全角スペースが入っている
- はじめに```# -*- coding: utf-8 -*-```を書かずに日本語を使用している（コメント含む）
	
#さいごに

画像編集をする際に毎回同じ操作をしているなと思ったらスクリプトを作成して自動化しましょう！！

さいごに１つ、大抵の場合だれかがすでにスクリプトを作ってくれているので自作するよりもネットでスクリプトを探す方が断然早いです。

#参考

- [GIMP (GNU 画像編集プログラム)](https://docs.gimp.org/ja/index.html)
- [Python を使用して GIMP 用のプラグインを作成する](https://www.ibm.com/developerworks/jp/opensource/library/os-autogimp/index.html)
- [PythonでGIMPのスクリプトを書く（Python-Fuの書き方）](http://d.sunnyone.org/2014/10/pythongimppython-fu.html)
- [GIMP Python Documentation](https://www.gimp.org/docs/python/#gimp_module_procedures)
- [GIMPで画像を一括でレベル補正（Python-Fu）](https://qiita.com/7shi/items/3253d5766a4c65cb1a1f)

#訂正（2018/01/13）
すみません。python-fuのスクリプトを置く場所を間違えてました。
×Library/Application Support/GIMP/2.8/scripts
○Library/Application Support/GIMP/2.8/plug-ins