Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

【最小構成】pythonのpillowモジュールを使ってタピオカミルクティーの画像に「100円」の文字を合成する

More than 1 year has passed since last update.

目的

きっかけはLINE Botのリッチメニュー。
これは自分で作ったとあるBotなんですが、画面下部にあるリッチメニューをタップすると、
それに見合った応答が返ってくるようになっています。

MicrosoftTeams-image.png

さて、今回のポイントはリッチメニューの部分です。
これ、実はボタンでもなんでもなくタダの画像です(現状LINEの仕組み上は画像で表現するしかないっぽい・・・)。

で、これが作りにくいんです。
そんなイイ感じのアプリは残念ながら持っていなかったので、パワポとペイントを使って切り貼りしています。まあそれなりにイイ出来だとは思うんですけど、時間がかかってしまいました。
(追記:最近のアップデートで、LINE Developers画面で簡単に作成できるようになっていました!)

そこで「それ、Pythonでできるんじゃね?」と思って調べていたところ
pillowなるモジュールでできそうなことが判明!
早速ですがやり方を見ていきましょう。

インストール

Python使いならもう慣れっこですが、とりあえずモジュールのインストールを行います。

$ pip install pillow

ちなみにpillowはPILというモジュールのフォークプロジェクトらしいです。
公式ドキュメントはココ
今回は主にこのドキュメントを参考に、画像処理をやっていきたいと思います。

既存の画像に文字を描く

今回はこのタピオカの画像に「100円」と入れてみたいと思います。
いきなりコードから行きます。

main.py
from PIL import Image, ImageDraw, ImageFont

#元画像を読み込んでくる
image = Image.open("tapioca.png")

#文字を書きこむ為のオブジェクトが用意されているので取得する
draw = ImageDraw.Draw(image)

#フォントを指定する(フォントファイルはWindows10ならC:\\Windows\\Fontsにあります)
#sizeは文字サイズです(とりあえず適当に50)
font = ImageFont.truetype("YuGothL.ttc", size=50)

#文字を描く
#最初の(0,0)は文字の描画を開始する座標位置です もちろん、(10,10)などでもOK
#fillはRGBで文字の色を決めています
draw.text((0, 0), "100円", fill=(255,0,0), font=font)

#画像を保存する
image.save("new_tapioca.png")

こんな感じになりました。
new_sample.png

応用(センタリング等)

文字の配置を弄ってみようと思います。
ドキュメントを見ている限りでは、そういうオプションがあったのですがどういうわけかうまく行かなかったので、絶対にうまくいく原始的な方法を考えました。

画像サイズを取得してみる

main.py
from PIL import Image, ImageDraw, ImageFont

#元画像を読み込んでくる
image = Image.open("tapioca.png")

#画像のサイズを取得する
print(image.size[0]) # => 今回の例では771
print(image.size[1]) # => 今回の例では856

これで最大のサイズがわかりました。

画像全体の中心から描画を開始してみる

上記の771と856を描画開始位置にしてしまうと、画像の右下から始まってしまい、せっかくの文字がほとんど見えません。
では、771と856を2で割り、その位置を開始位置にしてみます。
これで画像の中央部分から描画が始まるはずです。

new_sample.png

まあわかっていましたがこうなりますね。
開始地点はたしかに画像のど真ん中ですが、こうじゃない・・・。

さらに「100円」の描画領域のサイズを取得し、その半分の値分だけ場所を引き戻す

ちょっとタイトルがわかりにくいですが、「100円」の中心を画像全体の中心と合わせたいわけです。
つまり、「100円」が描画されるときのサイズを取得し、その上で「100円」のサイズの半分だけ開始地点を戻してやれば実現できます。う~ん、言葉にするのが難しい。

とりあえずやってみます。
まず、「100円」自体のサイズは以下で取得できました。

from PIL import Image, ImageDraw, ImageFont

#元画像を読み込んでくる場合
image = Image.open("tapioca.png")

#文字を書きこむ為のオブジェクトが用意されているので取得する
draw = ImageDraw.Draw(image)

#フォントを決める
font = ImageFont.truetype("YuGothL.ttc", size=50)

#「100円」のサイズを取得
draw_text_width, draw_text_height = draw.textsize("100円", font=font)

まず「100円」の描画開始地点を元画像の中心部分とした上で
このdraw_text_width、draw_text_heightの半分のサイズだけ、上と左に引き戻します。
上のコードの続きと考えてください。

draw.text(((image.size[0] / 2 - draw_text_width / 2), (image.size[1] / 2 - draw_text_height / 2)), "100円", fill=(255, 0, 0), font=font)

長くて分かりづらいですね。
こうしたほうがわかりやすいかも知れません。

start_X_point = image.size[0] / 2 - draw_text_width / 2
start_Y_point = image.size[1] / 2 - draw_text_height / 2

draw.text((start_X_point, start_Y_point), "100円", fill=(255, 0, 0), font=font)

完成コード

main.py
from PIL import Image, ImageDraw, ImageFont

#元画像を読み込んでくる場合
image = Image.open("tapioca.png")

#文字を書きこむ為のオブジェクトが用意されているので取得する
draw = ImageDraw.Draw(image)

#フォントを決める
font = ImageFont.truetype("YuGothL.ttc", size=50)

#描きたい文字のサイズを取得する
draw_text_width, draw_text_height = draw.textsize("100円", font=font)

#描きたい文字のサイズと元画像のサイズを元に、描画開始ポイントの座標を決める
start_X_point = image.size[0] / 2 - draw_text_width / 2
start_Y_point = image.size[1] / 2 - draw_text_height / 2

#描画する
draw.text((start_X_point, start_Y_point), "100円", fill=(255, 0, 0), font=font)

#出来上がった画像を保存する
image.save("new_tapioca.png")

これでめでたく真ん中に持ってくることができました。

new_sample.png

まとめ

・画像と文字の合成はPillowでカンタンにできる!
・合成するだけならカンタンだけど、センタリングとかは若干面倒かも
 (ドキュメント読む限りではセンタリングするオプションがあるんですけどね、なぜかうまく行かない...)

bow_arrow
Java、NodeJS、Python等色々やっております。日本のITリテラシを大きく引き上げ、世間に広くIT技術を広めて「自分の必要なものは自分でも作れる」、そんな世界になったらDXが進むのではないかと思っています。会社ではIT教育事業に携わっています。
https://www.comture.com/network/education.html
comture
コムチュアグループは、デジタルトランスフォーメーション(DX)時代を担う「デジタルソリューションパートナー」として、デジタル技術を活用し、お客様の経営課題解決とイノベーション推進を積極的に進めています。※各記事はすべて個人の見解であり、コムチュアグループの公式見解ではありません。
https://www.comture.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away