Pythonで絵文字入りの文字列を画像に埋め込む
Pythonで画像に文字を埋め込みたい場合、第一に候補として挙がってくるのはPillowだと思います。Pillowは広く使用されており、参考になる記事も豊富です。しかし、残念ながらPillowにはフォントのフォールバック機能がありません。多くのフォントは、グリフ数の上限などの理由から、通常の文字用と絵文字用のフォントファイルを分けています。
そのため、フォールバック機能がないPillowでは、一つのフォントしか指定できず、カスタムフォントを作成しない限り、絵文字か通常の文字のどちらか一方しか描画できません。
しかし、「圧倒的感謝👍」のような通常の文字と絵文字が混在する文字列を簡単に画像に埋め込みたいと思っていたとき、以下の便利なライブラリに出会いました。
https://github.com/nathanielfernandes/imagetext-py
まさに私が求めていたライブラリです。ただドキュメントがまだ充実しているわけではなく、私の環境ではExample Usageが上手く動作しないこともありました。そこで、使い方などを簡単に解説していきたいと思います。
準備:
pip install pillow
pip install imagetext-py
フォントをGoogle Fontsからダウンロードします。今回はNoto Sans Japaneseを使用します。こちらのリンクから、右上にあるDownload Familyからフォントをダウンロードすることができます。ダウンロードができたら、解凍をして中にあるNotoSansJP-Bold.ttfをプログラムを実行する階層と同じ場所に移してください。
Example Code:
from PIL import Image
from imagetext_py import *
FontDB.SetDefaultEmojiOptions(EmojiOptions(source=EmojiSource.Twemoji))
FontDB.LoadFromPath('NotoSansJP', './NotoSansJP-Bold.ttf')
font = FontDB.Query('NotoSansJP')
image = Image.open('./template.png')
cv = Canvas.from_image(image)
text = '圧倒的感謝👍ワンころ🐶気まぐれ🐈カフェイン☕ball🥎ハリネズミ🦔'
draw_text_wrapped(canvas=cv,
text=text,
x=945, y=620,
ax=0.5, ay=0.5,
size=90,
width=800,
font=font,
fill=Paint.Color((0, 0, 0, 255)),
align=TextAlign.Center,
stroke=2.0,
stroke_color=Paint.Color((0, 0, 0, 255)),
draw_emojis=True,
wrap_style=WrapStyle.Character)
im: Image.Image = cv.to_image()
im.save("output.png")
通常の文字に加えて、絵文字も正常に表示されていることが確認できます。それでは次に、コードの各処理について見ていきたいと思います。
from PIL import Image
from imagetext_py import *
FontDB.SetDefaultEmojiOptions(EmojiOptions(source=EmojiSource.Twemoji))
FontDB.LoadFromPath('NotoSansJP', './NotoSansJP-Bold.ttf')
font = FontDB.Query('NotoSansJP')
- Apple
- Microsoft
- Samsung
- JoyPixels
- OpenMoji
- Emojidex
- Messenger
- Mozilla
- Lg
- Htc
- Twemoji
image = Image.open('./template.png')
cv = Canvas.from_image(image)
draw_text_wrapped(canvas=cv,
text=text,
x=945, y=620,
ax=0.5, ay=0.5,
size=90,
width=800,
font=font,
fill=Paint.Color((0, 0, 0, 255)),
align=TextAlign.Center,
stroke=2.0,
stroke_color=Paint.Color((0, 0, 0, 255)),
draw_emojis=True,
wrap_style=WrapStyle.Character)
この関数で画像に文字列を埋め込んでいます。指定したwidthを超える場合は自動で改行を行ってくれます。引数が何を示しているかは基本的に名前の通りなので一部の引数についてのみ触れようと思います。
im: Image.Image = cv.to_image()
im.save("output.png")
draw_text_multiline
text = '圧倒的感謝👍ワンころ🐶\n気まぐれ🐈カフェイン☕\nball🥎ハリネズミ🦔'
draw_text_multiline(canvas=cv,
lines=text.split('\n'),
x=945, y=620,
ax=0.5, ay=0.5,
size=90,
width=800,
font=font,
align=TextAlign.Center,
fill=Paint.Color((0, 0, 0, 255)),
line_spacing=1.5,
draw_emojis=True)