プログラムでおかえしできるかな

定年を過ぎて何かの役に立てないかなと始めた元SEのブログです

コラージュ処理をPython-Fuスクリプトでバッチ処理【GIMP】

このエントリーをはてなブックマークに追加

4枚の画像(写真)を上下左右に並べて1枚にするコラージュ画像を自動で作るツールを作成したので紹介します。

画像編集ソフトの GIMP とそのスクリプトを利用してバッチファイルにしています。

目次

◆概要

以前、こちらの記事で4つの画像を上下左右に並べて一つの画像にする GIMP の操作方法を紹介しました。
この記事で操作していることを自動でできるようにしました。

この記事の操作方法では、境界線を画像の上に描画するため、弱冠ですが、画像の一部が隠れます。
今回、自動化するにあたり、画像の一部が隠れないように作成しました。
ちょっと進歩しています。

では、作り方を説明します。

作り方より使い方が知りたい方はこちらをクリックしてください。
取得方法と使い方 ⤵

自動化するのには、GIMP が提供しているスクリプト言語を使用します。
今回は、Python-Fu という Python を言語としたスクリプトを使います。

4つの画像をドラッグアンドドロップで指定するために、バッチファイルも用意しました。

日本語対応のためにバッチファイルは二つに分けています。
工夫した点は次の通りです。

Python-Fu スクリプトをバッチで動かす基本的な説明は、こちらの記事に掲載しています。
 📖 Python-Fuスクリプトでバッチ処理【GIMP】 🔗

以下、それぞれのバッチやスクリプトについて説明します。

◆起動用バッチ(Shift-JIS)

画像ファイルをドラッグして UTF-8 のバッチファイルを起動するバッチです。

画像ファイルのドラッグが4つ未満の場合にエラーを表示して終了します。
画像ファイルのドラッグが4つ以上の場合、4つの画像のパスを引数にして UTF-8 のバッチファイルを呼び出します。

先にも述べましたが、Python-Fu スクリプトで日本語を扱いたいので、スクリプトファイルは文字コードUTF-8 にします。
バッチファイルで日本語を扱う場合、文字コードを Shift-JIS にしておいた方が扱いやすいです。
 (コードページを変えれば UTF-8 でも可能ですが、他にも対応が必要で面倒です)

したがって、起動用のバッチファイルは Shift-JIS で作成して、UTF-8 で作成したバッチファイルを呼び出します。

▽起動用バッチファイル

@echo off

if "%4"=="" (
echo 4つの画像をドラッグしてください
echo 終了します
pause
exit
)

@echo カレントフォルダ:%CD%
@echo バッチのフォルダ:%~dp0

start %~dp0gimp_fu_collage.bat %1 %2 %3 %4

%~dp0 は変数 %0 がバッチファイルのパスを示し、~dp はそのうちドライブ名とパスのみを取得することを示します。

Python-Fuスクリプトを起動するバッチ(UTF-8)

このバッチは、GIMPコマンドラインオプションで Python-Fu スクリプトを起動します。
このバッチの一番の目的は、Python-Fu スクリプトに引数を渡すことです。
しかし、引数の渡し方が分からなかったので、Pyton-Fu スクリプトファイルを読み込み、引数で渡す部分を文字列の置換で対応し、一時ファイルに保存します。
保存した一時ファイルを指定して GIMP を起動します。

このバッチファイルは、文字コードUTF-8Python-Fu スクリプトファイルを読み書きするため、文字コードUTF-8 にして作成します。

Python-Fuスクリプトを起動するバッチ

rem python-fuのファイルをバッチで実行する
@echo off
chcp 65001

setlocal
setlocal enabledelayedexpansion

rem shori:起動方法(1:通常起動、2:コンソール起動)
set shori=2
rem 通常起動用exeの指定
set gimp1="C:\Program Files\GIMP 2\bin\gimp-2.10.exe"
rem コンソール起動用exeの指定
set gimp2="C:\Program Files\GIMP 2\bin\gimp-console-2.10.exe"
rem バッチの存在フォルダ:%~dp0 末尾に\が付く
rem 本ファイルと同じフォルダにあるPythonスクリプトファイルの指定

set scriptpath=%~dp0fu_collage4bat.py
set scripttemp=%~dp0fu_collage4bat.tmp

for /f "delims=" %%a in (%scriptpath%) do (set script=!script!%%a^


)

set script=!script:image_file_name1=%1!
set script=!script:image_file_name2=%2!
set script=!script:image_file_name3=%3!
set script=!script:image_file_name4=%4!

if %shori%==2 set script=!script:123456=False!

echo !script! > !scripttemp!

if %shori%==1 (
!gimp1! -n -c -d -s -f --batch-interpreter=python-fu-eval -b - -b "pdb.gimp_quit(1)" < !scripttemp!
goto :end
)
if %shori%==2 (
!gimp2! -i -n -c -d -s -f --batch-interpreter=python-fu-eval -b - -b "pdb.gimp_quit(1)" < !scripttemp!
goto :end
)
:end
endlocal
pause
exit

以下に主要な部分を説明します。

UTF-8のバッチファイルの作成方法

バッチファイルを UTF-8 で作成するには、次の二つのことを実施します。

  • コードページを指定する
    chcp 65001
  • ファイルを UTF-8 で保存する

◇ファイルの全内容を変数に入れる

バッチでは、for /f コマンドを使用してファイルの内容を取得します。
for /f コマンドは、ファイルの中身を一行ずつ処理するのが主な用途なので、全行を変数に入れるには、改行を追加する必要があります。

  • for コマンドのコマンド拡張機能 /f を指定
  • delims には何も指定しない指定(行全体を取得)
  • 改行文字として ^(改行)(改行) を指定
    ※(改行)は実際の改行
  • setlocal enabledelayedexpansion を指定して
    変数は遅延環境変数(!変数名!)を使用

▽file.txt の全内容を変数 str に入れるコード

setlocal enabledelayedexpansion

for /f "delims=" %%a in (file.txt) do (set str=!str!%%a^


)

※二行の改行が改行コードとして保持されます。
※改行を変数にしておく例もあったが、うまくいかないケースがあったので採用しませんでした。

◎変数の内容をファイルに出力

GIMP コマンドの batch オプションでスクリプトを変数で与えられなかったので、一時ファイルに出力することにしました。

変数の内容をファイルに出力するのは簡単で echo コマンドとリダイレクトでできます。

▽変数の内容をファイルに出力するコード

echo !str! > file.tmp

◇変数の内容を置換

バッチファイル内で変数の文字列の置換が行えます。
変数は通常 %変数名% で表されますが、後ろの % の前に変換式を入れます。

 ◇変数の置換 %変数名:置換前文字列=置換後文字列%

▽置換部分のコード

set script=!script:image_file_name1=%1!
set script=!script:image_file_name2=%2!
set script=!script:image_file_name3=%3!
set script=!script:image_file_name4=%4!

if %shori%==2 set script=!script:123456=False!

1行目は、変数 script 内の image_file_name1 を第一引数の内容で置き換えて再度、変数 script に入れています。

置換しているもの

  • 読み込む画像のパス(image_file_name)
  • GIMP を表示するかどうかのフラグ(shori)

◆4つの画像をコラージュするPython-Fuスクリプト(UTF-8)

スクリプトは、こちらの記事で紹介している手順をコードにしたものです。
 📖 画像(写真)を4分割レイアウトにコラージュ【GIMP】 🔗

使用している関数の調べ方はこちらの記事で紹介しています。
 📖 Python-Fuスクリプトでバッチ処理【GIMP】 🔗

◇コラージュの手順

スクリプトに記述するコラージュ作成の手順を示します。
使用している関数(記述は Python-Fu 用にしてあります)も示します。

  1. 画像を生成
    pdb.gimp_image_new(width, height, type) -> image
  2. 画像ファイルをレイヤーに読み込む(1枚ずつ4枚それぞれのレイヤーに)
    pdb.gimp_file_load_layer( image, filename) -> layer
  3. レイヤーを画像に追加
    pdb.gimp_image_insert_layer( image, layer, parent, position)
    parent:None(レイヤーグループに属さない)
    position:トップが0で以降+1
  4. キャンバスのサイズをレイヤーに合わせる
    pdb.gimp_image_resize_to_layers(image)
  5. 画像を縮小(ここでは幅を半分に)
    1回の操作で4枚まとめて縮小できます
    pdb.gimp_image_scale( image, new-width, new-height)
    レイヤーごとに縮小します(不揃いな解像度に対応)
    pdb.gimp_layer_scale( layer, new-width, new-height, local-origin)
  6. キャンバスのサイズをレイヤーに合わせる(念のため)
    pdb.gimp_image_resize_to_layers(image)
  7. キャンバスサイズの変更(作成する画像のサイズに)
    pdb.gimp_image_resize( image, new-width, new-height, offx, offy)
  8. 縮小した画像を整列(4枚それぞれ別の位置へ)
    pdb.gimp_layer_set_offsets(layer, offx, offy)
  9. 新規レイヤーを作成(グリッド(境界線)用)
    pdb.pdb.gimp_layer_new( image, width, hight, type, name, opacity, mode) -> layer
  10. レイヤーを追加(グリッド(境界線)用)
    pdb.gimp_image_insert_layer( image, layer, parent, position)
  11. グリッド(境界線)を作成
    pdb.plug_in_grid(引数)
    引数の詳細はこちら ⤵
  12. レイヤーをマージ
    pdb.gimp_image_merge_visible_layers( image, merge-type)
    merge-type:EXPAND_AS_NECESSARY (0), CLIP_TO_IMAGE (1), CLIP_TO_BOTTOM_LAYER (2)
  13. エクスポートして画像を作成
    pdb.gimp_file_save(image, drawable, filename, rqw-filename)

Python-Fu スクリプト

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from gimpfu import *
import gimpcolor

_width = 800                           # 完成画像の幅(1つの画像の幅ではない)
border_width = 10                      # 境界線の幅(偶数で)
_color = gimpcolor.RGB(211, 211, 2111)   # 色のRGBを指定(255,255,255は白)

_debug = 123456                            # デバッグ用バッチで変更するのでここでは変更不可
offset = border_width // 2
# コラージュ画像の幅、高さ、生成画像の高さを計算
_swidth = (_width - border_width * 3) // 2  # 横に2分割した時のコラージュ画像の幅
_sheight = _swidth * 3 // 4   # コラージュ画像の高さ アスペクト比4:3で計算
_height = (_sheight * 2) + (border_width * 3)   # 生成画像の高さ

_type = 0 # RGB(0), GRAY(1), INDEXED(2)
# ダミーの名前を定義、後で置換して目的のファイル名にする
_files = (r'image_file_name1', 
            r'image_file_name2', 
            r'image_file_name3',  
            r'image_file_name4')

pdb.gimp_message("My Python-fu開始(My Python-fu start)")
img = pdb.gimp_image_new(_width, _height, _type)
layer_ids = []
for _filename in _files:
    layer_id = pdb.gimp_file_load_layer(img, _filename)
    layer_ids.append(layer_id)
    pdb.gimp_image_insert_layer(img, layer_id, None, 0)    # parent(None):no group, position(0):top

pdb.gimp_image_resize_to_layers(img)                # キャンバスのサイズをレイヤーに合わせる
# pdb.gimp_image_scale(img, _swidth, _sheight)     # 画像の拡大縮小
for _layer in layer_ids:
    pdb.gimp_layer_scale(_layer, _swidth, _sheight, TRUE)
pdb.gimp_image_resize_to_layers(img)                # キャンバスのサイズをレイヤーに合わせる

pdb.gimp_message("images scaled to w:{}, h:{}".format(_swidth, _sheight))
pdb.gimp_image_resize(img, _width, _height, 0, 0) # キャンバスのサイズ変更

pdb.gimp_message("整列開始(Alignment start)")
pdb.gimp_layer_set_offsets(layer_ids[0], border_width, border_width)
pdb.gimp_layer_set_offsets(layer_ids[1], _swidth + border_width * 2, border_width)
pdb.gimp_layer_set_offsets(layer_ids[2], border_width, _sheight + border_width * 2)
pdb.gimp_layer_set_offsets(layer_ids[3], _swidth + border_width * 2, _sheight + border_width * 2)

pdb.gimp_message("グリッドフィルター開始(Start grid filter)")
# グリッド用レイヤーの作成(画像、幅、高さ、タイプ(1:RGBA(透明付 ))、名前、透明度、モード)
grid = pdb.gimp_layer_new(img, _width, _height, 1, "grid", 100, 0)
pdb.gimp_image_insert_layer(img, grid, None, 0)    # parent(None):no group, position(0):top
pdb.gimp_message("グリッドレイヤー作成完(Grid layer created)")
# グリッド(レガシー)
# 画像、対象、水平線幅、間隔、オフセット、色、透明度(0-255)、垂直線高さ、間隔、オフセット、色、透明度、交点幅、間隔、オフセット、色、透明度
hspace_width = _width // 2 - offset
vspace_width = _height // 2 - offset
# pdb.gimp_message('bd:{}, hspace:{}, vspace:{}'.format(border_width, hspace_width, vspace_width))
pdb.plug_in_grid(img, grid, border_width, vspace_width, offset, _color, 255
                          , border_width, hspace_width, offset, _color, 255
                          , 0, 0, 0, _color, 0)
pdb.gimp_message("グリッド作成完(Grided)")

if _debug:
    pdb.gimp_display_new(img)
    pdb.gimp_message("イメージ表示(image display)")

# 表示されているレイヤーをマージして一つのレイヤーに
layer = pdb.gimp_image_merge_visible_layers(img, EXPAND_AS_NECESSARY)

# 画像の保存
from datetime import datetime
out_f_name = "GIMP" + datetime.now().strftime('%y%m%d%H%M') + ".jpg"
pdb.gimp_file_save(img, layer, out_f_name, "")

※1:コラージュする画像の高さを幅から求めるよう変更
   生成画像の高さをコラージュする画像の高さと境界線幅から求めるように変更 更新:2023-10-06

◇グリッドの描画(レガシー)

スクリプトで使用できる関数に GIMP のメニューで提供されているグリッドが存在しません。
レガシー 1 と呼ばれるものが存在したので、こちらを使用しました。

  • 【構文】plug-in-grid(run-mode, image, drawable, hwidth, hspace, hoffset, hcolor, hopacity, vwidth, vspace, voffset, vcolor, vopacity, iwidth, ispace, ioffset, icolor, iopacity)
  • 引数
    • image:画像
    • drawable:対象
    • hwidth水平線幅
    • hspace:間隔(>=1)
    • hoffset:オフセット
    • hcolor:色
    • hopacity:透明度
    • vwidth垂直線高
    • vspace:間隔(>=1)
    • voffset:オフセット
    • vcolor:色
    • vopacity:透明度
    • iwidth交点の幅
    • ispace:間隔(>=0)
    • ioffset:オフセット
    • icolor:色
    • iopacity:透明度

※透明度は、0-255
※色の指定は RGB。gimpcolor.RGB() で指定可能。import gimpcolor が必要

※オフセットについて
 外周も境界線と同じ幅にするにはオフセットに境界線の幅/2を設定します。
 間隔はオフセットした分短く設定します。
 *2分割なのでこのようにしましたが、3分割以上なら、外周は別途描画する方が良いかもしれません。

◎2分割する場合の考え方(参考)

  • 一辺の構成:境界(10)---境界(10)---境界(10)
  • 全幅(800)
  • 1画像の幅:(800-10*3)/2

◆取得方法と使い方

ツールの取得方法と使い方を説明します。

◇取得と保存

スクリプトファイルとバッチファイルを含んだ zip ファイルを下記からダウンロードして取得します。
ダウンロードした zip ファイルを解凍すると次のファイルができます。(他にもreadmeなどが入っています)
任意のフォルダにファイルを保存してください。

  • スクリプトファイル:fu_collage4bat.py
  • 起動用バッチ   :gimp_collage.bat
  • GIMP起動用バッチ :gimp_fu_collage.bat

個別にはこちらから取得できます。

◇動作環境

◇起動方法

  1. エクスプローラなどでコラージュしたい4つの画像を選択(Ctrl を押しながらクリック)
  2. gimp_collage.bat に4つの画像をドラックアンドドロップ
  3. 4つの画像があるフォルダに GIMPyymmddhhmm.jpg 画像が作成されます

表示順について エクスプローラーでドラッグする場合、画像の表示順は、エクスプローラーに表示されている順です。
表示順を調整したい場合、エクスプローラーの表示を名前順にし、ファイル名を変更して希望の順にしてください。

◇設定方法

取得した fu_collage4bat.py ファイルを修正することで次の項目を調整できます。

  • 作成される画像の幅  :_width = 800 の800を変更(px)
  • 4つの図形の境界線の幅:border_width = 10 の10を変更(px)
  • 境界線の色      :_color = gimpcolor.RGB(211, 211, 2111) の数字を変更
    RGB の値の求め方はこちらを参照してください。
    色の指定の仕方⤵

fu_collage4bat.pyテキストエディタ(メモ帳でも大丈夫です)などで修正します。

▽コードの設定可能な部分

_width = 800                          # 完成画像の幅(1つの画像の幅ではない)
border_width = 4                       # 境界線の幅(偶数で)
_color = gimpcolor.RGB(0, 0, 0)          # 色のRGBを指定(255,255,255は白)

◎色の指定の仕方

色は RGB で指定します。

例えば、こちらのサイト『WEB色見本 原色大辞典 - HTMLカラーコード で色を見つけます。

色に貼ってあるリンクをクリックすると色の情報が出るので、そこから RGB の値を取得します。

◇実行結果の例

実行すると次の様な画面が表示されます。

「batch command excecuted successfully」と出ていれば、画像ファイルができています。
任意のキーを押して画面を閉じてください。

▽動作画面

日本語が出ない場合 UTF-8 で実行しているバッチの画面で日本語が出ない場合、コマンドプロンプトの画面で左上のアイコンをクリックして、プロパティ⇒フォントを選び、フォントを「MSゴシック」に変更してください。
コマンドプロンプトはShift-JISの状態で実施します。

ドラッグアンドドロップする画像の数が足りないと次の様な画面が出ます。

▽画像の数が少くない時のエラー画面

▽出来上がった画像

◇制限事項

  • 横向きでアスペクト比が 4:3 の画像が対象です
  • コラージュする画像の解像度は同じものが対象です 追加:2023-09-13

GIMPのインストール

GIMPのインストールはこちらのサイトが詳しいです。

◆更新情報

  • 2023-10-06 1.1.1
    • コラージュ画像の縮小が縦に短い問題を修正
  • 2023-09-13 1.0.2
    • コラージュする画像の解像度が不揃いな場合に対応
  • 2023-09-08 1.0.1
    • 画像サイズと作成する画像サイズが異なる時に正しく縮小できていなかったのを修正
  • 2023-09-07 1.0.0:初期リリース

更新:2023-10-06

◆さいごに

今回提供しているファイルは、私が使用しているウィルス検索ソフトのアバスト無料版でチェックして問題なしです。
ですが、実行時に検閲されることがありました。
「IDP.HELU.PBot4」や「IDP.Generic」が検出されたとして隔離されてしまいました。
仕方がないので復元したり、例外にしたりして動かしていました。

もし同じような環境の方がいて、同じようになってしまったら、申し訳ございませんが、例外にしてください。

ソースコードを公開しているので、ウィルスが入っていないことは確認していただけると思います。


ここで紹介したものと同じ機能のものを GUIPython にして作成しています。

後日、紹介できると思います。


あわせて読みたい GIMPでコラージュ:📖 画像(写真)を4分割レイアウトにコラージュ【GIMP】 🔗
GIMPスクリプト:📖 Python-Fuスクリプトでバッチ処理【GIMP】 🔗
GUI 付き:📖 コラージュ処理をPython-FuスクリプトでPythonのGUIを付けて【GIMP、Python】 🔗

◇ご注意

本記事は次のバージョンの下で動作した内容を基に記述しています。

◇免責事項

ご利用に際しては、『免責事項』をご確認ください。
お気づきの点がございましたら『お問い合わせ』からお問い合わせください。

投稿: 、更新:

  1. ヘルプサイト:14.21. Grid (legacy)