注目キーワード
  1. Photoshop
  2. Python
  3. Raspberry Pi
  4. Arduino

PythonとPILを使ったサムネイル作成を自動化する方法

  • 2020年11月27日
  • 2020年11月27日
  • Python

ここでは「Python」をコマンドプロンプト環境下で使用し、サムネイル画像作成を自動化する方法を紹介します。

 

サムネイル画像作成を自動化する経緯は

・有料ソフトを使わずにサムネイル作成をしたい

・ロゴ入れなどの単純作業を自動化したい

からです。

 

この記事を読むことで

pythonを使ったサムネイル作成を自動化する方法

ロゴの追加を自動化する方法

リサイズ、テキスト入れの方法

などを学ぶことができます。

 

Pythonプログラムの一連の流れは

・ロゴ画像名、サムネタイトル名などの任意指定

・ロゴのリサイズ&追加(左右上下対応)

・テキストのリサイズ&追加(中央)

と実行されます。

 

今回Pythonでサムネイル作成を自動化するときに気を付けたポイントは

・読み込んだサムネイル画像のサイズに合わせたロゴ、テキストのリサイズ

・サムネイルタイトルの複数読み込みに対応

になります。

 

まず、画像に合わせたロゴ、テキストのリサイズができないと

taku
ロゴ、テキストが読み込んだ画像のサイズに合ってない…

となり、サムネイルに使うには見栄えしない状態になります。

 

続いて、サムネイルのタイトルを複数読み込めないと、一括で複数のサムネイルを作ることができません。

これでは自動化する意味が薄くなってしまうと思ったので、こちらにも対応しました。

 

では、一通りPythonでサムネイル作成をする目的・概要をお話したところで、実際にプログラムの説明・解説・プログラム全文を見ていきましょう。

 

Pythonでサムネイル作成を始める前の準備

まずはサムネイル作成を自動化するプログラムをPythonで書く前に、動作環境の構築・実行ファイルの場所&内容などを確認しておきましょう。

 

Pythonの動作環境

今回実行を行った動作環境は以下の通りです。

OS:Windows10

テキストエディター:TeraPad(Visual Studioもたまに)

Pythonバージョン:3.7.5

 

2020/11/27日現在の最新バージョンは「Python:3.9.0」ですが、3系バージョンなら大抵は動作します。

Pythonのバージョン確認はコマンドラインで

python –version

python -V

などで確認することができます。

 

必要なpip install

今回、サムネイル作成自動化プログラムで必要なpip installは以下の1つになります。

 

pip install Pillow

Pillowは画像の切り抜き、リサイズ、編集を行うことができるライブラリになります。

 

他にも「インポート」として「os」、「sys」を呼び出しますが、標準ライブラリに含まれているので、追加でインストールする必要はありません。

 

Pythonファイルなどの作成場所

続いて、Pythonプログラムの場所とその中身について確認しておきます。

 

今回は、同一ファイル内(カレントディレクトリ内)に

・サムネイル対象の画像

・サムネイルに使うロゴ画像

・Pythonプログラム

を用意しています。

 

(↓ 下図参考)

logo-thumbnail-create-01

サムネイル画像やロゴ画像を別のファイルから参照したい場合は、別途プログラムを書き換え、Pathを参照し画像を読み込めるようにしてくださいね。

 

Pythonサムネイル作成に必要な関数

それでは、実際にプログラムの内容と解説に進んでいきます。

 

サムネイルのフォント・タイトルを決める

まずはサムネイルのフォント・色・タイトルなどを決めていきます。

# coding: UTF-8
import os
import sys
from PIL import Image, ImageDraw, ImageFont

logo_name = 'blog-top-picture.png'    # ロゴ画像のファイル名を「logo_name」に格納

create_folder_name = 'thumbnail_file'    # 作成用ファイルの名前を定義
os.makedirs(create_folder_name, exist_ok=True)    # カレントディレクトリに※※ファイルを作成

font_size = 96    # フォントサイズを指定
font_color = 'fuchsia'    # フォント色を指定
title = ['No Rain No Rainbow.' ,
         'Everything is practice.' ,
         'If you want to be happy,be.' ,
         'Information in not knowledge.' ,
         'Every day is a new day.' ,
         'To live is to think.' ,
         'Hope is a waking dream.' ,
         'Stay hungry. Stay foolish']
    # サムネイルタイトルを設定

 

サムネイルに追加するロゴの名前を

logo_name = ‘ ※※※※※※※※ ‘

として格納します。

 

ここで、ロゴに使用する画像の「フルパス」を渡してやれば、別のフォルダーからも定義可能です。

 

続いて

create_folder_name = ‘thumbnail_file’ # 作成用フォルダーの名前を定義

os.makedirs(create_folder_name, exist_ok=True) # カレントディレクトリに※※フォルダーを作成

は、サムネイル作成をし終わった画像を入れるフォルダーを用意しています。

 

os.makedirs(フォルダー名, exist_ok=True)

で指定フォルダー名のフォルダーを作成することができるので、始めて知った方は是非覚えておきましょう。

 

logo-thumbnail-create-03
実際に実行すると、上図のように作成したファイルが、指定したフォルダーに入っていることが確認できます。

 

最後にサムネイルに追加するフォントのサイズ・色・タイトルを指定します。

font_size = 96 # フォントサイズを指定

font_color = ‘fuchsia’ # フォント色を指定

# サムネイルタイトルを設定
title = [‘No Rain No Rainbow.’ ,

‘Everything is practice.’ ,

‘If you want to be happy,be.’ ,

‘Information in not knowledge.’ ,

‘Every day is a new day.’ ,

‘To live is to think.’ ,

‘Hope is a waking dream.’ ,

‘Stay hungry. Stay foolish’]

 

フォントの色を今回は「’ fuchsia ‘」という濃いピンク色にしていますが、wikiなどで指定できるウェブカラーの色と名称が記載されているので、そちらを参考にしてください。

 

ウェブカラーで使える色と名称-wiki

 

また、サムネイルのタイトルは「配列」を使って格納しておきます。

取り敢えず8つのタイトルを用意しておきましたが

作成するサムネイルの枚数 <= タイトルの配列

となっていれば、エラーなく動作ができます。

 

逆にタイトルの配列がサムネイルの枚数に足りないとエラーが発生するので注意してください。

 

サムネイルの上下左右にロゴを追加

サムネイルに追加する文字サイズ・色・テキストが決まったら、続いてロゴをサムネイルの上下左右好きな箇所に追加します。

def logo_add(f_name, l_name):    # ロゴの追加

    # リサイズ&リサイズ後の縦×横を返す
    resize_width, resize_height = 960, 540    # サムネイル対象画像のリサイズ設定値を定義
    img = Image.open(f_name)    # カレントディレクトリの画像を開く
    img.thumbnail( (resize_width, resize_height) )    # 指定サイズを超える場合、リサイズ
    width, height = img.size    # リサイズ後の画像サイズ or 開いた画像の画像サイズを格納

    logo_resize_width, logo_resize_height = 200, 200    # ロゴ画像のリサイズ設定値を定義
    logo_img = Image.open(l_name)
    logo_img.thumbnail( (logo_resize_width, logo_resize_height) )    # 指定サイズを超える場合、リサイズ
    logo_width, logo_height = logo_img.size    # ロゴのサイズを格納

    while True:
        logo_img.thumbnail( (logo_resize_width, logo_resize_height) )    # 指定サイズを超える場合、リサイズ
        logo_width, logo_height = logo_img.size    # ロゴのサイズを格納
        if width > logo_width:    # サムネイル画像の幅 > ロゴ画像の幅
            break    # while文をbreak
        else:    # ロゴ画像の幅がサムネイル画像の幅より以上のとき
            logo_resize_width, logo_resize_height = logo_resize_width // 4, logo_resize_height // 4    # 1/4倍へ

    print('画像:{0} にロゴ:{1} を追加します。'.format(f_name, l_name))

    # ロゴ追加場所を指定
    img.paste(logo_img, (0, 0), logo_img)    # 左上
    #img.paste(logo_img, (0, height - logo_height), logo_img)    # 左下
    #img.paste(logo_img, (width - logo_width, 0), logo_img)    # 右上
    #img.paste(logo_img, (width - logo_width, height - logo_height), logo_img)    # 右下

    return img    # ロゴを追加した画像をimgとしてreturn

 

まず、読み込むサムネイルの画像が大きすぎる場合はリサイズをします。

# リサイズ&リサイズ後の縦×横を返す

resize_width, resize_height = 960, 540 # サムネイル対象画像のリサイズ設定値を定義

img = Image.open(f_name) # カレントディレクトリの画像を開く

img.thumbnail( (resize_width, resize_height) ) # 指定サイズを超える場合、リサイズ

width, height = img.size # リサイズ後の画像サイズ or 開いた画像の画像サイズを格納

 

上記では「16:9」の比率になるような「960:540」をリサイズ上限値として定義しました。

リサイズ値は任意に決めてもらって構いません。

これを

img.thumbnail( (resize_width, resize_height) )

と宣言することで、リサイズ値を超えた場合にリサイズすることができます。

 

あとは、リサイズ後のサイズを「width、height」に格納しておきます。

「logo_resize_width、logo_resize_height」下の4行も同様の内容です。

 

続いて、ロゴがサムネイル画像より大きい場合の処理をします。

while True:

logo_img.thumbnail( (logo_resize_width, logo_resize_height) ) # 指定サイズを超える場合、リサイズ

logo_width, logo_height = logo_img.size # ロゴのサイズを格納

if width > logo_width: # サムネイル画像の幅 > ロゴ画像の幅

break # while文をbreak

else: # ロゴ画像の幅がサムネイル画像の幅より以上のとき

logo_resize_width, logo_resize_height = logo_resize_width // 4, logo_resize_height // 4 # 1/4倍へ

 

「width > logo_width」とロゴ画像よりもサムネイル画像が大きい場合はwhileループを抜け出し

「width <= logo_width」のときロゴサイズを1/4倍

にリサイズします。(「width <= logo_width」はelseで省略)

 

このプログラムがあるだけで、自動的にリサイズ処理がされるので画像サイズの違いによってエラーが発生することがなくなります。

 

最後に、ロゴを追加する場所を決めましょう。

# ロゴ追加場所を指定

img.paste(logo_img, (0, 0), logo_img) # 左上

#img.paste(logo_img, (0, height – logo_height), logo_img) # 左下

#img.paste(logo_img, (width – logo_width, 0), logo_img) # 右上

#img.paste(logo_img, (width – logo_width, height – logo_height), logo_img) # 右下

 

追加場所は「左上下、右上下」の4箇所になり

サムネイル画像の幅 - ロゴ画像の幅

という計算をすることで、ロゴの位置を右側に寄せることができます。

この辺りはお好きな位置を「コメントアウト( # )」で選んでくださいね。

 

これらの処理でロゴの追加ができたので「return img」とロゴ追加した画像を返して、ロゴ追加用の関数は終了です。

 

サムネイルの中央にテキストを追加

ロゴの追加ができたら、サムネイル画像の中央にテキストを追加していきます。

def font_add(img, f_name, f_size, color, title):

    width, height = img.size    # リサイズ後の画像サイズ or 開いた画像の画像サイズを格納
    draw = ImageDraw.Draw(img)    # ImageDraw.Draw(img)宣言を draw へ置き換え

    while True:
        title_font = ImageFont.truetype('msmincho.ttc', f_size, index = 1)    # MS P明朝 
        title_w, title_h = draw.textsize(title, font = title_font)
        if width > title_w:
            break
        else:
            f_size = (f_size // 3) * 2

    draw.text( ( (width - title_w)/2 ,  (height - title_h)/2 ), title, fill = color , font = title_font)

    return = img    # テキストを追加した画像をimgとしてreturn

 

まずは、ロゴを追加した「img」データを引数から取り入れ

width, height = img.size # リサイズ後の画像サイズ or 開いた画像の画像サイズを格納

draw = ImageDraw.Draw(img) # ImageDraw.Draw(img)宣言を draw へ置き換え

と記述し「img」データのサイズと画像を読み込みます。

 

続いて、読み込んだサムネイル画像のサイズとサムネタイトルのサイズを比較し

while True:

title_font = ImageFont.truetype(‘msmincho.ttc’, f_size, index = 1)     # MS P明朝

title_w, title_h = draw.textsize(title, font = title_font)

if width > title_w:

break

else:

f_size = (f_size // 3) * 2

 

「width > title_w」ならWhileループを抜け出し

「width <= title_w」のときタイトルサイズを2/3倍

にリサイズをします。(「width <= title_w」はelseで省略)

 

サムネタイトルもリサイズすることで、画像からタイトルがはみ出るというエラーもなくなることが以下の図からも分かると思います。

 

画像サイズ:800×450

logo-thumbnail-create-04

 

画像サイズ:1280×987

logo-thumbnail-create-05

 

画像サイズ:1920×1080logo-thumbnail-create-06

 

またテキストを上図のように中央配置するために

draw.text( ( (width – title_w)/2 , (height – title_h)/2 ), title, fill = color , font = title_font)

とします。

 

中央配置は

サムネ横幅の中央値 - タイトル横幅の中央値

と計算することで中央配置が可能なので、一度具体的な数値を使って各々確認してみてください。

 

最後に、テキストを追加した画像を「return」で返して終了です。

 

メイン文でカレントディレクトリをループ

関数を作成し終わったので、メイン文を書いていきます。

if __name__ == '__main__':
    count = 0
    # カレントディレクトリの全画像をループ
    for filename in os.listdir('.'):
        if not (filename.endswith('.png') or filename.endswith('.jpg')) or filename == logo_name:
            continue    # png、jpgでない、またはlogo_nameのときは続行
        add_img = logo_add(filename, logo_name)
        add_img = font_add(add_img, filename, font_size, font_color, title[count])
        add_img.save(os.path.join(create_folder_name, filename))
        count += 1
    print("プログラムを終了します。")
    sys.exit()

 

for文は「カレントディレクトリ内のファイル全て」をループするよう宣言しており

if not (filename.endswith(‘.png’) or filename.endswith(‘.jpg’)) or filename == logo_name:

continue # png、jpgでない、またはlogo_nameのときは続行

と記述することで、

.pngでない .jpgでない 選択したロゴ画像のときはスキップ

する処理をしています。

 

あとは、上記で作成した関数を使って「ロゴの追加」、「テキストの追加」、「画像の保存」をして終了です。

 

メイン文の「count」はテキストの配列を動かすためのカウンタになります。

sys.exit()はプログラムを終了させる文になります。

 

Python サムネイル作成プログラム全文

では最後にPythonでサムネイル作成を自動化するプログラム全文を紹介しますね。

プログラムを動作させるときは

cd C:\※※\※※

と実行ファイルのPathへ移動し実行します。

logo-thumbnail-create-02

 

また、下記のプログラム全文中の

logo_name = ‘ ※※※※※※※※ ‘
 
create_file_name = ‘ ※※※※※※※※.png ‘
 
font_size = ※※font_color = ‘ ※※ ‘
 
title = [ ‘ ※※※※※※※※ ‘ ,  … ]

などは各自変えて必要に応じて変えてくださいね。

 

thumbnail.py 全文

# coding: UTF-8
import os
import sys
from PIL import Image, ImageDraw, ImageFont

# ImageDraw Module : https://pillow.readthedocs.io/en/latest/reference/ImageDraw.html
# ImageFont_Path:C:\Windows\Fonts

logo_name = '※※※※※※※※.png'    # ロゴ画像のファイル名を「logo_name」に格納

create_file_name = '※※※※※※※※'    # 作成用ファイルの名前を定義
os.makedirs(create_file_name, exist_ok=True)    # カレントディレクトリに※※※※※※※※ファイルを作成

font_size = 96    # フォントサイズを指定
font_color = 'fuchsia'    # フォント色を指定
title = ['No Rain No Rainbow.' ,
         'Everything is practice.' ,
         'If you want to be happy,be.' ,
         'Information in not knowledge.' ,
         'Every day is a new day.' ,
         'To live is to think.' ,
         'Hope is a waking dream.' ,
         'Stay hungry. Stay foolish']
    # サムネイルタイトルを設定(任意)

def logo_add(f_name, l_name):    # ロゴの追加

    # リサイズ&リサイズ後の縦×横を返す
    resize_width, resize_height = 960, 540    # サムネイル対象画像のリサイズ設定値を定義
    img = Image.open(f_name)    # カレントディレクトリの画像を開く
    img.thumbnail( (resize_width, resize_height) )    # 指定サイズを超える場合、リサイズ
    width, height = img.size    # リサイズ後の画像サイズ or 開いた画像の画像サイズを格納

    logo_resize_width, logo_resize_height = 200, 200    # ロゴ画像のリサイズ設定値を定義
    logo_img = Image.open(l_name)
    logo_img.thumbnail( (logo_resize_width, logo_resize_height) )    # 指定サイズを超える場合、リサイズ
    logo_width, logo_height = logo_img.size    # ロゴのサイズを格納

    while True:
        logo_img.thumbnail( (logo_resize_width, logo_resize_height) )    # 指定サイズを超える場合、リサイズ
        logo_width, logo_height = logo_img.size    # ロゴのサイズを格納
        if width > logo_width:    # サムネイル画像の幅 > ロゴ画像の幅
            break    # while文をbreak
        else:    # ロゴ画像の幅がサムネイル画像の幅より以上のとき
            logo_resize_width, logo_resize_height = logo_resize_width // 4, logo_resize_height // 4    # 1/4倍へ

    print('画像:{0} にロゴ:{1} を追加します。'.format(f_name, l_name))

    # ロゴ追加場所を指定
    img.paste(logo_img, (0, 0), logo_img)    # 左上
    #img.paste(logo_img, (0, height - logo_height), logo_img)    # 左下
    #img.paste(logo_img, (width - logo_width, 0), logo_img)    # 右上
    #img.paste(logo_img, (width - logo_width, height - logo_height), logo_img)    # 右下

    return img    # ロゴを追加した画像をimgとしてreturn

def font_add(img, f_name, f_size, color, title):

    width, height = img.size    # リサイズ後の画像サイズ or 開いた画像の画像サイズを格納
    draw = ImageDraw.Draw(img)    # ImageDraw.Draw(img)宣言を draw へ置き換え

    while True:
        title_font = ImageFont.truetype('msmincho.ttc', f_size, index = 1)    # MS P明朝 
        title_w, title_h = draw.textsize(title, font = title_font)
        if width > title_w:
            break
        else:
            f_size = (f_size // 3) * 2

    draw.text( ( (width - title_w)/2 ,  (height - title_h)/2 ), title, fill = color , font = title_font)

    img.save(os.path.join(create_file_name, filename))

if __name__ == '__main__':
    count = 0
    # カレントディレクトリの全画像をループ
    for filename in os.listdir('.'):
        if not (filename.endswith('.png') or filename.endswith('.jpg')) or filename == logo_name:
            continue    # png、jpgでない、またはlogo_nameのときは続行
        add_img = logo_add(filename, logo_name)
        font_add(add_img, filename, font_size, font_color,  title[count])
        count += 1
    print("プログラムを終了します。")
    sys.exit()

 

 

また当サイトでは、IBM Watsonを使ったPythonによる「画像分析」として

[Graspy:AI初心者向け講座感想]IBM WatsonとPythonによる画像分析

 

といった記事や

 

Python 指定フォルダ先のPNG→JPEG変換を自動化する方法

といった「自動化プログラム」について発信しているので、興味がある方は是非ご覧になってみてくださいね!

 

お疲れ様でした。

logo-thumbnail-create-top
学びに関する情報をチェック!