【Pillow入門 第3回】画像に文字や図形を描画!ImageDrawモジュール活用術 🎨✍️

「画像に注釈として矢印や枠線を入れたいんだけど、どうすればいい?」
「写真に自分の名前やコピーライト表記(透かし文字)を入れたいな。」
「ブログ用のサムネイル画像を、Pythonで自動生成できたら最高なのに!」

こんにちは! Python画像処理探検隊、隊長のPythonistaです! 前回の第2回では、ImageEnhanceImageFilterを使って、画像の明るさ調整やフィルター処理といった本格的な画像加工テクニックを学びましたね。写真の雰囲気を自在に変えられるようになり、Pillowの面白さが深まったのではないでしょうか。

シリーズ第3回の今回は、既存の画像を加工するだけでなく、画像の上に新しい要素、つまり文字や図形を自由に描画する方法を学びます。これを実現するのが、Pillowの強力なImageDrawモジュールです。このモジュールを使いこなせば、画像への注釈入れ、ウォーターマークの追加、そしてオリジナルのサムネイル画像作成まで、あなたのアイデア次第で様々なクリエイティブな画像生成が可能になります。さあ、Pillowで真っ白なキャンバスに絵を描くように、画像描画の世界を探検しましょう!


1. 準備:ImageDrawImageFontモジュール

まず、描画に必要なモジュールをインポートし、描画の土台となる画像を用意しましょう。

1.1. モジュールのインポート

画像の上に描画を行うには、Imageクラスに加えて、描画機能を提供するImageDrawと、フォントを扱うためのImageFontをインポートします。

from PIL import Image, ImageDraw, ImageFont
import os

# 加工した画像を保存するディレクトリを作成
output_dir = 'drawing_examples'
os.makedirs(output_dir, exist_ok=True)

1.2. 描画の土台(キャンバス)となる画像の準備

既存の画像ファイルを開いてその上に描画することも、全く新しい無地の画像を作成して描画することもできます。今回は、新しい無地の画像を作成してみましょう。

# 800x600ピクセル、背景色を薄いグレーにした新しい画像を作成
canvas_width = 800
canvas_height = 600
background_color = (240, 240, 240) # RGB値で指定
img = Image.new('RGB', (canvas_width, canvas_height), background_color)

print("新しいキャンバス画像を作成しました。")
# img.show()

1.3. 描画コンテキストの作成

Pillowで画像に描画を行うには、まず「描画コンテキスト」と呼ばれる、描画操作専用のオブジェクトを作成する必要があります。これはImageDraw.Draw()関数を使います。

# Imageオブジェクトを渡して、Drawオブジェクト(描画コンテキスト)を作成
draw = ImageDraw.Draw(img)
print("描画コンテキストを作成しました。これからこの'draw'オブジェクトを使って描画します。")

これ以降の描画操作は、すべてこのdrawオブジェクトのメソッドを呼び出す形で行います。描画された内容は、元のimgオブジェクトに直接反映されていきます。


2. 基本図形の描画:線、長方形、円を描いてみよう

まずは、基本的な図形を描く方法をマスターしましょう。

2.1. 線の描画 (draw.line())

draw.line(xy, fill=None, width=0)

  • xy: 座標のリスト。[(x1, y1), (x2, y2), ...]のように指定します。2点なら直線、3点以上なら折れ線になります。
  • fill: 線の色。色の指定方法は後述します。
  • width: 線の太さ(ピクセル単位)。
# 赤色の直線を引く (左上から右下へ)
draw.line([(50, 50), (750, 550)], fill='red', width=5)

# 青色の折れ線を引く
draw.line([(50, 550), (400, 100), (750, 550)], fill='blue', width=3)

print("\n直線と折れ線を描画しました。")
# img.show()

色の指定方法: 色は、'red'のような色の名前(英語)、'#FF0000'のような16進数カラーコード、(255, 0, 0)のようなRGB値のタプルなどで指定できます。

2.2. 長方形の描画 (draw.rectangle())

draw.rectangle(xy, fill=None, outline=None, width=1)

  • xy: 長方形の左上の座標と右下の座標を(左x, 上y, 右x, 下y)のタプルまたはリストで指定します。
  • fill: 塗りつぶしの色。
  • outline: 枠線の色。
  • width: 枠線の太さ。
# 緑色で塗りつぶされた長方形
draw.rectangle((100, 150, 300, 300), fill='green')

# 黄色の枠線を持つ、塗りつぶしなしの長方形
draw.rectangle((350, 150, 550, 300), outline='yellow', width=10)

# 紫の枠線を持つ、水色で塗りつぶされた長方形
draw.rectangle((600, 150, 700, 300), fill='#87CEEB', outline='purple', width=5)

print("長方形を描画しました。")
# img.show()

2.3. 円や楕円の描画 (draw.ellipse())

draw.ellipse(xy, fill=None, outline=None, width=1)

このメソッドは、指定した四角形の領域(バウンディングボックス)に内接する楕円を描画します。完全な円を描きたい場合は、正方形の領域を指定します。

  • xy: 楕円が内接する長方形の左上と右下の座標を(左x, 上y, 右x, 下y)で指定。
# 黒い枠線の楕円
draw.ellipse((100, 350, 350, 500), outline='black', width=5)

# オレンジ色で塗りつぶされた円 (正方形の領域を指定)
draw.ellipse((400, 375, 550, 525), fill='orange')

print("楕円と円を描画しました。")
# img.save(os.path.join(output_dir, 'sample_shapes.png'))



3. 画像に文字を描画する

画像にテキストを追加するのは、注釈やタイトル、ウォーターマークなど、多くの場面で役立ちます。

3.1. フォントの準備と読み込み (ImageFont.truetype())

任意のフォントやサイズでテキストを描画するには、まずフォントファイルを読み込んでImageFontオブジェクトを作成する必要があります。TrueTypeフォント(.ttf)やOpenTypeフォント(.otf)が利用できます。

OSにインストールされているフォントのパスを指定するか、スクリプトと同じディレクトリにフォントファイルを置いてパスを指定します。今回は、多くのPCにインストールされているであろう「Arial」フォントを仮定しますが、見つからない場合もあるため、Google Fontsなどで好きなフォントをダウンロードして使うのが確実です。

# フォントファイルのパスを指定
# Windowsの場合: "C:/Windows/Fonts/arial.ttf"
# macOSの場合: "/System/Library/Fonts/Supplemental/Arial.ttf"
# Linuxの場合: パスは環境による。なければ好きな.ttfファイルをダウンロードして使うのが簡単。
font_path = "arial.ttf" # 仮にカレントディレクトリにあるとする

try:
    # フォントサイズを指定してImageFontオブジェクトを作成
    font_large = ImageFont.truetype(font_path, 60)
    font_small = ImageFont.truetype(font_path, 24)
    print("\nフォントを読み込みました。")
except IOError:
    print(f"警告: フォントファイル '{font_path}' が見つかりません。デフォルトフォントを使用します。")
    font_large = ImageFont.load_default()
    font_small = ImageFont.load_default()

3.2. テキストの描画 (draw.text()) と配置

draw.text(xy, text, fill=None, font=None, anchor=None, ...)

  • xy: テキストを描画する開始位置の座標(x, y)
  • text: 描画する文字列。
  • fill: テキストの色。
  • font: 作成したImageFontオブジェクト。
  • anchor (Pillow 8.0.0以降): テキストのどの部分をxy座標に合わせるかの基準点(アンカー)を指定する便利な引数。例えば'lt'(左上、デフォルト)、'mm'(中央)、'ms'(中央下)など。

サンプルコード:

# テキストを描画 (アンカーを使わない基本形)
draw.text((50, 20), "Pillow ImageDraw 入門", font=font_small, fill='black')

# テキストを画像の中央に配置する
# まず、描画したいテキストとフォントを準備
title_text = "Hello, Pillow!"

# Pillow 8.0.0以降で推奨される簡単な方法 (anchor='mm')
# 画像の中央座標 (width/2, height/2) を指定し、アンカーを 'mm' (middle-middle) にする
center_x = canvas_width / 2
center_y = canvas_height / 2
draw.text((center_x, center_y), title_text, font=font_large, fill='darkblue', anchor='mm')

# 古いバージョンや、より手動で制御したい場合の方法 (textbboxを使う)
# bbox = draw.textbbox((0, 0), title_text, font=font_large)
# text_width = bbox[2] - bbox[0]
# text_height = bbox[3] - bbox[1]
# position_x = (canvas_width - text_width) / 2
# position_y = (canvas_height - text_height) / 2
# draw.text((position_x, position_y), title_text, font=font_large, fill='darkblue')

# 右下にコピーライト表記を入れる (ウォーターマーク風)
copyright_text = "© 2025 Pythonista"
draw.text((canvas_width - 20, canvas_height - 40), copyright_text, font=font_small, fill='gray', anchor='rb') # 'rb' = right-bottom

print("テキストを描画しました。")
# img.save(os.path.join(output_dir, 'sample_text.png'))
# img.show()

テキストの配置は少し計算が必要な場合がありますが、Pillow 8.0.0以降で導入されたanchor引数を使うと、中央揃えなどが非常に簡単になります。



6. 実践!ブログ用サムネイル画像を自動生成しよう

最後に、これまでのテクニックを組み合わせて、ブログ記事用のシンプルなサムネイル画像を生成する関数を作ってみましょう。

from PIL import Image, ImageDraw, ImageFont
import os

def create_thumbnail(title, subtitle, output_filename, width=1200, height=630):
    """シンプルなブログ用サムネイルを生成する関数"""
    bg_color = (25, 25, 112)  # Midnight Blue
    title_color = '#FFFFFF' # White
    subtitle_color = '#FFD700' # Gold
    
    img = Image.new('RGB', (width, height), bg_color)
    draw = ImageDraw.Draw(img)

    # フォントをロード (パスは環境に合わせてください)
    try:
        title_font = ImageFont.truetype('arialbd.ttf', 80) # Arial Bold
        subtitle_font = ImageFont.truetype('arial.ttf', 40)
    except IOError:
        title_font = ImageFont.load_default()
        subtitle_font = ImageFont.load_default()
        print("警告: 指定フォントが見つからないため、デフォルトフォントを使用します。")

    # タイトルを中央に描画
    draw.text((width / 2, height / 2), title, font=title_font, fill=title_color, anchor='mm')
    
    # サブタイトルをタイトルの下に描画
    draw.text((width / 2, height / 2 + 80), subtitle, font=subtitle_font, fill=subtitle_color, anchor='mm')
    
    # 簡単な装飾線
    draw.line([(width / 2 - 200, height / 2 + 140), (width / 2 + 200, height / 2 + 140)], fill=subtitle_color, width=3)
    
    img.save(output_filename)
    print(f"\nサムネイル '{output_filename}' を作成しました。")
    # img.show()

# 関数を実行してサムネイルを作成
if __name__ == "__main__":
    create_thumbnail(
        title="Python Pillow 入門",
        subtitle="ImageDrawモジュールで描画マスター!",
        output_filename=os.path.join(output_dir, 'thumbnail_sample.png')
    )



まとめ:ImageDrawで画像表現はもっと自由に!

今回は、Pillow入門シリーズの第3回として、ImageDrawモジュールを使った画像への描画方法について学びました。

  • ImageDraw.Draw()で描画コンテキストを作成すること。
  • 基本的な図形(線、長方形、円・楕円)の描画方法。
  • ImageFontモジュールでフォントを準備し、draw.text()テキストを描画する方法。
  • anchor引数やtextbbox()メソッドを使った、テキストの正確な配置テクニック。

これらの機能を組み合わせることで、単なる画像加工に留まらず、レポート用の注釈入り画像、コピーライト表記の入った写真、そしてブログやSNS用のオリジナル画像などを、Pythonプログラムで自動的に生成できるようになります。あなたのアイデア次第で、Pillowの可能性は無限に広がります。

Pillow入門シリーズは今回で一区切りとしますが、Pillowには他にも画像の合成やGIFアニメーションの作成など、面白い機能がたくさんあります。ぜひ公式ドキュメントなども参考に、さらなる画像処理の世界を探求してみてください!

その他の投稿はこちら

コメント

このブログの人気の投稿

タイトルまとめ

これで迷わない!WindowsでPython環境構築する一番やさしい方法 #0

【Python標準ライブラリ完結!】11の冒険をありがとう!君のPython力が飛躍する「次の一歩」とは? 🚀