Python 3 (v3.4.8) + ImageMagick > 複数画像を切出して合成する v0.1: ソース内の設定で動く | v0.2: JSONファイルから設定を読込む

```txt:動作環境
CentOS release 6.9 (Final)
GNU Bash-4.1
ImageMagick Version: ImageMagick 6.7.2-7 2017-03-22 Q16
Python 3.4.8
```

### 関連

- [bash + ImageMagick > rainbow colorのボックスを作る v0.1](https://qiita.com/7of9/items/be6f435675a8e6a106e6)

### 概要

- 複数の画像ファイルを合成する
- 切出し情報
    - srcPath: ファイルパス
    - cropSize: 切出しサイズ
    - srcLeftTop: 切出し左上座標
    - dstLeftTop: 合成先の左上座標
    
## code v0.1

### code

CONFIGSの設定を追加、削除することで、読込む画像数を変更可能。

```composeImages_180808.py
import subprocess as sb
import sys

# v0.1 Aug. 8, 2018
#   - compose images based on the config dictionary

#on Python 3.4.8

CONFIGS = [
    {
        'srcPath': 'DIR1/out.png',
        'cropSize': '100x100',
        'srcLeftTop': '+10+10',
        'dstLeftTop': '+50+10'
    },
    {
        'srcPath': 'DIR2/out.png',
        'cropSize': '80x80',
        'srcLeftTop': '+10+10',
        'dstLeftTop': '+50+120'
    },
    {
        'srcPath': 'DIR3/out.png',
        'cropSize': '110x110',
        'srcLeftTop': '+30+30',
        'dstLeftTop': '+140+120'
    }
]

#convert -crop 100x200+50+40 Main.png 2.png
#  100:height, 200:width
#  50:left, 40:top

DSTFILE = "cmp.png"  # composed file (final output)

#1. make background
BGSIZE = "300x300"  # background image size
BGFILE = "back.png"  # background file
acmd = "convert -size %s xc:white %s" % (BGSIZE, BGFILE)
print(acmd)
sb.getoutput(acmd)  # instead of Popen() to wait the process to finish

for acfg in CONFIGS:
    print("-----")
    #2. crop image
    CROPFILE = 'crop.png'
    params = (acfg['cropSize'], acfg['srcLeftTop'], acfg['srcPath'], CROPFILE)
    acmd = "convert -crop %s%s %s %s" % params
    print(acmd)
    sb.getoutput(acmd)

    #3. compose
    params = "%s %s %s %s" % (acfg['dstLeftTop'], CROPFILE, BGFILE, DSTFILE)
    acmd = "composite -compose over -gravity northwest -geometry %s" % params
    print(acmd)
    sb.getoutput(acmd)

    #4. update background
    acmd = "cp %s %s" % (DSTFILE, BGFILE)
    print(acmd)
    sb.getoutput(acmd)

# message
print("-----")
print("[%s] is produced" % DSTFILE)

```

### 実行時環境

[bash + ImageMagick > rainbow colorのボックスを作る v0.1](https://qiita.com/7of9/items/be6f435675a8e6a106e6)
で作成したout.pngファイルを下記のように配置する。

- DIR1/out.png
- DIR2/out.png
- DIR3/out.png

### 実行

```txt:run
$ python3 composeImages_180808.py 
convert -size 300x300 xc:white back.png
-----
convert -crop 100x100+10+10 DIR1/out.png crop.png
composite -compose over -gravity northwest -geometry +50+10 crop.png back.png cmp.png
cp cmp.png back.png
-----
convert -crop 80x80+10+10 DIR2/out.png crop.png
composite -compose over -gravity northwest -geometry +50+120 crop.png back.png cmp.png
cp cmp.png back.png
-----
convert -crop 110x110+30+30 DIR3/out.png crop.png
composite -compose over -gravity northwest -geometry +140+120 crop.png back.png cmp.png
cp cmp.png back.png
-----
[cmp.png] is produced
```

`eog cmp.png`した結果は以下。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/73875d4f-409b-4066-d224-eaf55ca174fb.png)

### 備考

subprocessの実行はPopen()でなくgetoutput()にした。
Popen()ではプロセスになり、処理が終わる前に後続の処理が実行される、という理解。

## code v0.2

CONFIGURATIONをJSONファイルから読込むように変更

- [Python 3 (v3.4.8) > JSONファイル読込み > 3セットのimageごとの各項目を標準出力する](https://qiita.com/7of9/items/403658c3c68445f5041f)

### code

```composeImages_180808.py
import subprocess as sb
import sys
import json

# v0.2 Aug. 8, 2018
#   - read CONFIGS from JSON file
# v0.1 Aug. 8, 2018
#   - compose images based on the config dictionary

#on Python 3.4.8

JSONFILE = 'config.json'

with open(JSONFILE) as reader:
    try:
        json_data = json.load(reader)
    except Exception as exc:
        print("Exception args:", exc.args)
        sys.exit()

#convert -crop 100x200+50+40 Main.png 2.png
#  100:height, 200:width
#  50:left, 40:top

DSTFILE = "cmp.png"  # composed file (final output)

#1. make background
BGSIZE = "300x300"  # background image size
BGFILE = "back.png"  # background file
acmd = "convert -size %s xc:white %s" % (BGSIZE, BGFILE)
print(acmd)
sb.getoutput(acmd)  # instead of Popen() to wait the process to finish

for images in json_data:
    for akey in images.keys():
        acfg = dict(images[akey])
        print("-----")
        #2. crop image
        CROPFILE = 'crop.png'
        prm = (acfg['cropSize'], acfg['srcLeftTop'], acfg['srcPath'], CROPFILE)
        acmd = "convert -crop %s%s %s %s" % prm
        print(acmd)
        sb.getoutput(acmd)

        #3. compose
        prm = "%s %s %s %s" % (acfg['dstLeftTop'], CROPFILE, BGFILE, DSTFILE)
        acmd = "composite -compose over -gravity northwest -geometry %s" % prm
        print(acmd)
        sb.getoutput(acmd)

        #4. update background
        acmd = "cp %s %s" % (DSTFILE, BGFILE)
        print(acmd)
        sb.getoutput(acmd)

# message
print("-----")
print("[%s] is produced" % DSTFILE)
```

### JSONファイル

```config.json
[
	{
		"image1": {
			"srcPath": "DIR1/out.png",
			"cropSize": "100x100",
			"srcLeftTop": "+10+10",
			"dstLeftTop": "+50+10"
		},
		"image2": {
			"srcPath": "DIR2/out.png",
			"cropSize": "80x80",
			"srcLeftTop": "+10+10",
			"dstLeftTop": "+50+120"
		},
		"image3": {
			"srcPath": "DIR3/out.png",
			"cropSize": "110x110",
			"srcLeftTop": "+30+30",
			"dstLeftTop": "+140+120"
		}
	}
]
```

### 実行

実行結果はv0.1と同じ。

### v0.2 はまる点

- JSONファイルのsrcPathに実在しないファイルパスを指定していると、処理の間違いに気づかない
- JSONファイルの同じkey(例: image1)のセットが複数指定された場合、片方しか処理されない

### 関連

- [Python2 + eog > 複数の画像をeogで開く | overlay_image_171003_execとの組合わせ例](https://qiita.com/7of9/items/b1071b0b8753098b6ad4)
- [ImageMagick | bash > 4枚の画像の重ね合わせ > overlay_image_171003_exec](https://qiita.com/7of9/items/d78fb76197bfdbda4b72)
- [ImageMagick | bash > white, blue, yellow, redの色を持つ4つのファイルを作成する > 同じサイズ | 異なるサイズ | 異なるサイズ+背景:透明](https://qiita.com/7of9/items/d17eca51b44daa2a2866)