見出し画像

Pillow(PIL)ライブラリを使って描画範囲内に収まるようにテキストサイズを自動調節する。【Python】

どうもsakamodです。今回はPillow(PIL)ライブラリでテキストサイズを自動調節するコードを作っていきたいと思います。この内容の記事自体は昔からあるのですが、どれもPillowのバージョンが古く現在では動作しないものも多いです。自分も結構ここで詰まったので過去の自分と同じ境遇の人の助けになればと思い記事を作りマス。
pillow==10.3.0(2024/06/16時点での最新ver)

※今回のPillowではlibqramモジュールが必須なので導入しておきましょう/
参考生地↓

完成したコード 関数にしてあるのでいつでも呼び出せます。

#Python

async def create_image(box_x, box_y, box_x2, box_y2, font_size, radius, image_path, color, font, text,storke_fill_c,stroke_width_s):
    image = Image.open(image_path).copy()
    font_kei = ImageFont.truetype(font,font_size)
    box_width = abs(box_x - box_x2)
    box_hight = abs(box_y - box_y2)
    box_anchr_x = box_x + (box_width/2)
    box_anchr_y = box_y + (box_hight/2)
    draw = ImageDraw.Draw(image)
    text_lengths = draw.textbbox((box_x,box_y),text,font=font_kei,direction= radius)
    text_width = abs(text_lengths[0] - text_lengths[2])
    text_hight = abs(text_lengths[1] - text_lengths[3])
    while(box_hight < text_hight or box_width < text_width):
        font_size -= 1
        font_kei = ImageFont.truetype(font,font_size)
        text_lengths = draw.textbbox((box_x,box_y),text,font=font_kei,direction= radius)
        text_width = abs(text_lengths[0] - text_lengths[2])
        text_hight = abs(text_lengths[1] - text_lengths[3])
    draw = ImageDraw.Draw(image)
    draw.text((box_anchr_x, box_anchr_y), text, color, font=font_kei,direction=radius,anchor="mm",stroke_fill=storke_fill_c,stroke_width=stroke_width_s)
    image.save("new.jpg")

コード解説

引数について(内容とかいいからとっとと使いたい人向け)

box_x :テキストの描画領域を箱状とした時の左上のX座標
box_y:テキストの描画領域を箱状とした時の左上のY座標
box_x2:テキストの描画領域を箱状とした時の右下のX座標
box_y2:テキストの描画領域を箱状とした時の右下のY座標
font_size:デフォルトのフォントサイズ、この値を初期値としてwhileで減数処理が行われる。
radius:テキストの左右上下(l,r,t,b)例,左から右に書く = ltr
          上から下 = ttb, ltr(left to right) ttb(top to bottom)
image_path:テキストを埋め込みたい画像のパス
color:テキストの色
font:テキストのフォントのパス
text:入力したいテキスト
storke_fill_c:文字の縁取り色
stroke_width_s:文字の縁取りの大きさ(0にすると縁取りなしになる)

最終的な画像はnew.jpgとして保存される。

細かい解説(理解したい人向け)

    image = Image.open(image_path).copy()
    font_kei = ImageFont.truetype(font,font_size)

imageに画像を代入する。font_keiにフォントのデフォルトのサイズとフォントを設定する。

    box_width = abs(box_x - box_x2)
    box_hight = abs(box_y - box_y2)

描画領域の横幅と高さを求める。

    box_anchr_x = box_x + (box_width/2)
    box_anchr_y = box_y + (box_hight/2)

描画領域の中心を求め、そこを基準に文字を描く

    draw = ImageDraw.Draw(image)
    text_lengths = draw.textbbox((box_x,box_y),text,font=font_kei,direction= radius)
    text_width = abs(text_lengths[0] - text_lengths[2])
    text_hight = abs(text_lengths[1] - text_lengths[3])

drawを定義して、テキストのサイズを仮で求めて代入する。

    while(box_hight < text_hight or box_width < text_width):
        font_size -= 1
        font_kei = ImageFont.truetype(font,font_size)
        text_lengths = draw.textbbox((box_x,box_y),text,font=font_kei,direction= radius)
        text_width = abs(text_lengths[0] - text_lengths[2])
        text_hight = abs(text_lengths[1] - text_lengths[3])

whileでテキストサイズがボックスサイズ(描画領域)よりも大きいなら
フォントサイズを-1する。
減らしたサイズでまたテキストサイズを求める。
条件に合致しなくなるまで比較、減少を繰り返す。

    draw = ImageDraw.Draw(image)
    draw.text((box_anchr_x, box_anchr_y), text, color, font=font_kei,direction=radius,anchor="mm",stroke_fill=storke_fill_c,stroke_width=stroke_width_s)
    image.save("new.jpg")

最後に最終的なテキストサイズでテキストを描いて保存して終わり。

・終わりに

自分はこの機能を使って簡単なコラ画像を作成して送信するDiscordのbotを作りました。いつかその記事も出そうと思います。最後まで見てくださりありがとうございます。

よろしければX(旧ツイッター)のフォローお願いします。↓

https://twitter.com/sakamod32


この記事が気に入ったらサポートをしてみませんか?