python Pillow(PIL) で画像を生成する

python Pillow(PIL) で画像を生成する

2024/01/18 00:00:00
Program
Python

前提 #

準備 #

python 3.11.7 の開発環境構築

$ mkdir python-image
$ cd python-image
$ pyenv local 3.11.7
$ python -m venv venv
$ source venv/bin/activate
$ pip install pillow
...
[notice] A new release of pip is available: 23.2.1 -> 23.3.2
[notice] To update, run: pip install --upgrade pip
# pip 更新の通知がでれば更新しておく
$ pip install --upgrade pip
# requirements.txt を作成しておく
# 作成済みの場合、 $ pip install -r requirements.txt でパッケージインストール可能
$ pip freeze > requirements.txt

# エディタで静的解析が必要な場合(poetry使わないと開発用パッケージが混ざるので注意)
$ pip install jedi flake8 importmagic autopep8 yapf black

画像生成 #

以下に画像を生成するサンプルを示す
サンプルソースは以下の内容を示している

  • サンプルアプリ実行時の入力引数の解析
  • フォントサイズからピクセル数に変換
  • フォントと線から画像1を作成
  • フォントと線から画像2を作成
  • 画像1と画像2を結合し新画像を作成
  • 新画像から各画像フォーマットファイルを作成
    • PNG
    • JPEG
    • GIF

$ emacs create_image.py

 1from PIL import Image, ImageDraw, ImageFont, ImageOps
 2import argparse
 3import traceback
 4
 5# フォントサイズは32.0としておく
 6FONT_SIZE = 32.0
 7# フォントは環境に応じて設定する
 8#  - windows: MS ゴシック: 'C:/Windows/Fonts/msgothic.ttc'
 9#  - ubuntu22.04: UbuntuMono: '/usr/share/fonts/truetype/ubuntu/UbuntuMono-RI.ttf'
10FONT_NAME = '/usr/share/fonts/truetype/ubuntu/UbuntuMono-RI.ttf'
11
12def font2PixcelSize(pt):
13    '''
14    フォントptからピクセルに変換
15    '''
16    return ((pt * 96.0) / 72.0)
17
18
19def mm2PixcelSize(mm):
20    '''
21    mm からピクセルに変換
22    '''
23    return ((mm * 96.0) / 27)
24
25
26def create_image(message):
27    width = 200
28    height = int(font2PixcelSize(FONT_SIZE))  # フォントサイズからピクセルの高さを計算
29    image = Image.new('RGB', (width, height), (255, 255, 255))  # width x height のピクセル画像エリアを作成し、背景色は白色にする
30    draw = ImageDraw.Draw(image)
31    # 色は色見本文字列でも指定可能 ex: 'Red': (255, 0, 0) 
32    #  https://www.colorhexa.com/color-names
33    draw.line((0, 0, width, 0), fill=(255, 0, 0), width=1)  # 上部に赤線を引いておく
34    draw.line((0, height-1, width, height-1), fill=(0, 255, 0), width=1)  # 下部に緑線を引いておく
35    font = ImageFont.truetype('/usr/share/fonts/truetype/ubuntu/UbuntuMono-RI.ttf', FONT_SIZE)
36    anchor = 'la' # la=左, ma=中央, ra=右
37    draw.text((0, 0), message, (0, 0, 0), spacing=0, align='left', anchor=anchor, font=font)  # message 文字列を描画する
38    return image
39
40
41def concat_image(base_image, add_image):
42    # サイズはbase_imageを基準にする
43    new_image = Image.new('RGB', (base_image.width, base_image.height + add_image.height))
44    new_image.paste(base_image, (0, 0))  # base_image を書き込み
45    new_image.paste(add_image, (0, base_image.height))  # add_image を base_image に下部に書き込み 
46    return new_image
47
48
49def main(args):
50    image1 = create_image('image1')  # 画像1を作成
51    image2 = create_image('image2')  # 画像2を作成
52    new_image = concat_image(image1, image2)  # 画像1と画像2を結合して新画像を作成
53    new_image.save(args.imagefile+'.PNG')  # 新画像からPNG 形式画像ファイルを出力。PNG指定はデフォルト。new_image.save(imagefile+'.PNG', 'PNG') と同じ
54    # 指定可能なフォーマットは PNG, JPEG, PPM, GIF, TIFF, BMP ... JPEG,GIF をサンプル出力しておく
55    new_image.save(args.imagefile+'.JPEG', 'JPEG')
56    new_image.save(args.imagefile+'.GIF', 'GIF')
57
58
59if __name__ == '__main__':  # プログラム実行ポイント
60    try:
61        # 入力引数設定
62        parser = argparse.ArgumentParser(description='png画像生成')
63        parser.add_argument('imagefile', help='image ファイル')  # 入力引数1:生成した画像を保存するファイル名
64        args = parser.parse_args()  # 入力引数取得
65        main(args)
66    except Exception:  # main() で発生する異常はすべてキャッチする
67        t = traceback.format_exc()
68        print("ERROR: {}".format(t))

実行

# test.xlsx は入力引数1番で、出力するexcelファイル名を示す
$ python create_image.py image
complete

参考UR #