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をプログラムを実行する階層と同じ場所に移してください。

次に文字を埋め込むための画像をtemplate.pngというファイル名で保存してください。本記事ではtemplate.pngとして以下の画像を使用します。


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')
1行目で使用する絵文字の種類を、2,3行目でフォントを指定しています。
今回は使用する絵文字としてTwemojiを指定していますが、以下の14種類を使用することが可能となっています。
  1. Twitter
  2. Apple
  3. Google
  4. Microsoft
  5. Samsung
  6. WhatsApp
  7. JoyPixels
  8. OpenMoji
  9. Emojidex
  10. Messenger
  11. Mozilla
  12. Lg
  13. Htc
  14. Twemoji
フォントの指定部分に関してなのですが、githubのExample UsageではFontDB.LoadFromDir(".")と書かれていたのですが私の環境ではエラーが出てフォントを読み込めなかったので、このような書き方をしています。

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を超える場合は自動で改行を行ってくれます。引数が何を示しているかは基本的に名前の通りなので一部の引数についてのみ触れようと思います。

align: テキストを何揃えにするか指定します。左揃えはTextAlign.Leftを、右揃えはTextAlign.Rightを、中央揃えはTextAlign.Centerを指定する必要があります。

draw_emojis: defaultではfalseになっていて、これをTrueにしておかないと絵文字が表示されません。

wrap_style: 自動改行の方式にはWrapStyle.CharacterとWrapStyle.Wordの2種類が存在し、それぞれ文字または語を基準に設定することが可能です。WrapStyle.Wordは主に英語のように単語間に空白が存在する言語向けです。したがって、日本語のように単語間に空白がない言語を扱う際は、WrapStyle.Characterを選択しておけば問題ないです。

ここで注意する必要があるのが、明示的な改行を含んだ文字列を入力しても意図した場所で改行を行ってくれるわけではないということです。明示的に改行を行いたい場合は、後述するdraw_text_multilineという関数を使用する必要があります。

im: Image.Image = cv.to_image()
im.save("output.png")
最後に文字列を埋め込んだ画像を保存しています。

draw_text_multiline

先ほど少し触れましたが、明示的に改行を指定したい場合はこの関数を使用する必要があります。draw_text_wrappedとほとんど同じで特段説明をする必要は無いと思われるため、サンプルのソースコードと出力される画像のみを以下に提示しておきます。
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)

まとめ

Pillowではフォントのフォールバック機能が提供されていない中、絵文字もどうしても表示したいとあがいていた所でこのimagetext-pyに出会えたのは幸運でした。ドキュメント等は特に無かったのですが、ソースコード部分に関数の説明等がしっかりと書いてあったので非常に使いやすかったです。また本文の方では触れなかったのですが、文字を画像に埋め込んだ後にその画像をpillowのImageに変換できる点も素晴らしいと思っています。このライブラリを作成してくださった方に圧倒的感謝👍
Next Post Previous Post