このページでは、Python の画像処理ライブラリの1つである Pillow のフォントについて説明していきます。
Pillow では ImageDraw
モジュールの text
メソッドを利用することで画像に文字列を描画することが可能です。そして、この text
メソッドでは font
引数を指定することで描画する文字列のフォントやサイズを指定することが可能です。
text
メソッドに関しては下記ページで詳しく説明していますので、text
メソッドの全般的な使い方に関しては下記ページをご参照いただければと思います。このページではフォントに焦点を当てて解説していきます。
例えば Mac であれば、下の図のようにフォントを Menlo や Helvetica に変更したり、
Windows であれば下の図のようにフォントをメイリオや MS ゴシックに変更したりするようなことができます。
また、同じフォントであっても、太字や斜体など細かなフォント指定も可能です。
さらに、フォントのサイズ(文字のサイズ)の変更も行うことができます。
では、これらのフォントやサイズの変更はどのようにすれば実現できるのでしょうか?
このページでは、上記で説明したようなフォント・サイズの変更方法について詳しく・分かりやすく解説していきます!上記のような Pillow でのフォントの扱い方に関して興味のある方は是非ページを読み進めていっていただければと思います!
Contents
フォントの変更(ImageFont
)
まずは、Pillow で文字列を描画する text
メソッドにおける “フォントを変更する” 方法について説明していきます。
この text
メソッドは ImageDraw
モジュールで定義される Draw
クラスのメソッドになります。text
メソッドに関しての詳細については別途下記ページで解説していますので、text
メソッド自体について知りたい方は下記ページを参照していただければと思います。
例えば下記は、msg
変数の参照する文字列を画像に描画するスクリプトの例となります。
from PIL import Image, ImageDraw
msg = 'Hello!'
# Imageオブジェクトの生成
image = Image.new('RGB', (200, 100), 'lightgray')
# Drawオブジェクトの生成
drawer = ImageDraw.Draw(image)
# 文字列の描画(textメソッドを実行)
drawer.text(xy=(0, 0), text=msg, fill='black')
# 文字列描画後の画像を表示
image.show()
実行すれば、下図のように灰色背景の画像に Hello
という文字列が描画されることになります。今回は灰色背景の画像を使ってフォントについて説明していきますが、Image.new
ではなく Image.open
を利用して Image
オブジェクトを生成するようにすれば任意の画像に文字列を描画することも可能となります。
文字列の描画は行えましたが、ちょっと文字のサイズが小さいですね…。また、もしかしたらフォントも気に入ってないかもしれません。
こういったフォントや文字のサイズに関しては、text
メソッドに font
引数を指定することで変更することが可能です。そして、この font
引数にはフォントオブジェクトを指定します。つまり、text
メソッドで描画される文字列のフォントは、この font
引数に指定するフォントオブジェクトによって決まることになります。
したがって、好みのフォントやサイズに応じたフォントオブジェクトを生成し、それを text
メソッド実行時に font
引数に指定するようにすることで、自由自在に描画する文字列のフォントやサイズを変更することができるようになります。
ということで、Pillow で描画する文字列のフォントを変更するためには、まずはフォントオブジェクトを生成してやる必要があることになります。
文字のサイズに関しては font
引数の指定以外の手段で変更することも可能です
これに関しては後述で解説します
フォントオブジェクトの生成
では、フォントオブジェクトはどのようにして生成すれば良いでしょうか?
次は、この点について説明していきます。
ImageFont.truetype
関数で生成
他にもやり方はあると思いますが、おそらく一番一般的なフォントオブジェクトの生成方法は ImageFont
モジュールを利用する方法になると思います。ImageFont
モジュールには truetype
関数が用意されており、この truetype
関数よりフォントオブジェクトを生成することが可能です。
そして、この truetype
関数では font
引数(第1引数)に利用したいフォントの “ファイルパス” を指定することで、そのフォントに基づいたフォントオブジェクトを生成することができます。
フォントの実体はファイルであり、その中で文字の形状などが定義されています。font
引数でファイルパスを指定することで、そのファイルに基づいたフォントオブジェクトを生成することが可能となります。このファイルの拡張子は .ttc
や .ttf
の場合がありますが、拡張子は省略して指定しても問題ありません。拡張子を省略した場合は単なるフォント名になる場合が多いです。
例えば MacOSX ではフォントのファイルとして Helvetica.ttc
が標準で用意されているはずで、この 'Helvetica.ttc'
を font
引数に指定してやることでフォントが Helvetica
であるフォントオブジェクトを生成することができます。拡張子を省略して 'Helvetica'
を指定しても問題ありません。
そして、このフォントオブジェクトを font
引数に指定して text
メソッドを実行すればフォント Helvetica
で文字列を描画することができます。
こんな感じで、フォントのファイルパスを引数に指定して ImageFont.truetype
関数を実行してフォントオブジェクトを生成し、それを font
引数に指定して text
メソッドを実行するのがフォントを指定した文字列描画の基本的な流れとなります。
指定可能なフォントのファイルパス
では、具体的に ImageFont.truetype
関数の font
引数に指定可能なパスにはどんなものがあるのでしょうか?
おそらく、Pillow でフォントを扱う上で一番難しいのはココになると思います。なぜ難しいのかというと、それは使用している PC によって指定可能なパスが異なるからになります。要は PC にインストールされているフォントのファイルパスのみを指定することが可能で、それ以外を指定すると例外が発生することになります。
特に OS によってインストールされているファイルが異なるため注意が必要になります。例えば上記の例で示した 'Helvetica.ttc'
は Mac をお使いの方であれば問題ありませんが、Windows を利用されている場合は指定すると例外が発生することになると思います。少なくとも私の PC で試したら例外が発生しました…。
File "C:\Users\daeu\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\PIL\ImageFont.py", line 245, in __init__ self.font = core.getfont( ^^^^^^^^^^^^^ OSError: cannot open resource
では、自身の PC で font
引数に指定可能なパスは具体的に何になるのでしょうか?
これを知る一番確実な方法はフォントのインストール先フォルダを実際に調べてみることになると思います。そのフォルダに存在するファイルのファイル名が、基本的に font
引数に指定可能なパスであると言えます。
そして、このフォントのインストール先フォルダは OS によって異なります。具体的な OS 毎のフォントのインストール先フォルダは下記となります。WINDIR
は Windows の環境変数として定義されているパスであり、基本的には C:¥windows¥
と定義されており、この場合の %WINDIR%¥fonts
は C:¥Windows¥fonts
を指すことになります。
- WIndows:
%WINDIR%¥fonts
- Mac:
/Library/Fonts/
/System/Library/Fonts/
~/Library/Fonts/
要は、ImageFont.truetype
を実行した際には、font
引数に指定されたパスを上記フォルダからの相対パスとしてファイルの検索が行われ、そのファイルが存在する場合はそのファイルからフォントの定義を読み込み、text
メソッド実行時にそのフォントの定義に従って文字列が描画されることになります。
そのため、font
引数に指定されたパス(上記のフォルダから見た相対パス)にファイルが存在しなければ ImageFont.truetype
関数で例外が発生することになります。逆に言えば、上記のフォルダに存在するファイルであれば、そのフォルダからの相対パスを font
引数に指定してやれば基本的に ImageFont.truetype
の実行は成功すると考えられます。そのため、font
引数に指定可能なパスを調べたい場合は、まずは上記のフォルダの中に存在するファイルを調べてみると良いでしょう。
上記では相対パスに対する説明に限定していますが、実際には直接フォントのファイルのパスを絶対パスで指定することも可能です
この場合、前述で示したフォルダ以外に存在するフォントも利用することが可能です
少し説明が長くなりましたが、Windows の場合、例えば下記を実行すれば MS ゴシックのフォントで文字列が描画されることになります。
from PIL import Image, ImageDraw, ImageFont
# 使用するフォント
font_name = 'msgothic.ttc'
# 描画する文字列
msg = 'Hello!'
# Imageオブジェクトの生成
image = Image.new('RGB', (200, 100), 'lightgray')
# Drawオブジェクトの生成
drawer = ImageDraw.Draw(image)
# フォントオブジェクトの生成
font = ImageFont.truetype(font=font_name)
# 文字列の描画(textメソッドを実行)
drawer.text(xy=(0, 0), text=msg, fill='black', font=font)
# 文字列描画後の画像を表示
image.show()
スクリプトを実行して表示される画像は下図のようなものになります。
また、Mac の場合、上記スクリプトの下記を実行すれば Helvetica のフォントで文字列が描画されることになります。
from PIL import Image, ImageDraw, ImageFont
# 使用するフォント
font_name = 'Helvetica.ttc'
# 描画する文字列
msg = 'Hello!'
# Imageオブジェクトの生成
image = Image.new('RGB', (200, 100), 'lightgray')
# Drawオブジェクトの生成
drawer = ImageDraw.Draw(image)
# フォントオブジェクトの生成
font = ImageFont.truetype(font=font_name)
# 文字列の描画(textメソッドを実行)
drawer.text(xy=(0, 0), text=msg, fill='black', font=font)
# 文字列描画後の画像を表示
image.show()
こちらのスクリプトを実行して表示される画像は下図のようなものになります。文字が小さいのでフォントの違いが分かりにくいですが、後述で紹介する手順でフォントサイズを大きくしてやればフォントによる違いがより明確になります。
ここまでの説明の通り、使用する PC、特に OS によって font
引数に指定可能なパスが異なります。ここから紹介するスクリプトでは基本的に font
引数に 'Helvetica.ttc'
を指定する例を示していきますので、特に Windows を利用されている場合は font
引数に指定するパスを自身の PC で使用可能なものに置き換えてから実行するようにしてください。
スポンサーリンク
スタイル(太字や斜体)の指定
先ほど説明したように、font
引数(第1引数)に使用したいフォントのファイルのパスを指定して ImageFont.truetype
関数を実行することでフォントオブジェクトを生成することが可能です。
そして、そのフォントオブジェクトを text
メソッド実行時に font
引数へ指定してやることで、描画する文字列のフォントを ImageFont.truetype
関数の font
引数に指定したファイルのフォントに変更することが可能となります。
ただ、Word や Power Point 等では文字列のフォントだけでなく、太字や斜体等のスタイルを設定することも可能です。Pillow で文字列を描画する際には、こういったスタイルを設定することはできないのでしょうか?
結論としては「できる」が答えとなります。ここからは、この “フォントのスタイル” の指定方法について説明していきます。
index
引数でフォントのスタイルを指定
前述の通り、ImageFont.truetype
関数でフォントオブジェクトを生成する際にはフォントのファイルのパスを指定して実行する必要があります。そして、このフォントのファイルには、実は複数種のフォントが定義されています。より具体的には、ファイルには太字や斜体・太字かつ斜体等の複数のスタイルのフォントが定義されています。
ImageFont.truetype
関数の index
引数
ImageFont.truetype
関数でフォントオブジェクトを生成する際に font
引数のみを指定した場合、生成されるフォントオブジェクトは指定したファイルの標準的なスタイルのフォントに基づいたものになります。
ですが、前述の通りファイルには複数のスタイルが定義されており、それらのスタイルの中から好みのものを指定してフォントオブジェクトを生成することも可能です。したがって、そのスタイルさえ指定さえしてやれば太字や斜体のフォントオブジェクトも生成することができます。
index
引数とスタイルの対応の調べ方
で、このスタイルは ImageFont.truetype
関数の index
引数によって指定することが可能です。index
引数には整数を指定します。
では、具体的に太字にしたい場合や斜体にしたい場合は index
引数に何を指定すれば良いのでしょうか?
これは実は一概には言えなくて、ファイル(フォント種)によって異なります。ですが、index
引数とスタイルとの対応は自力で簡単に調べることができます。
フォントオブジェクトには getname
というメソッドが用意されており、このメソッドを実行すればフォントオブジェクトのフォント名だけでなく太字や斜体などのスタイル名を取得することができます。したがって、とりあえず index
引数に整数を指定し、その時に生成されるフォントオブジェクトから getname
メソッドを実行させてやれば、その index
引数に対応するスタイルを確認することができます。ちょっと面倒ですが、スクリプトを用意しておけば調べるのも楽になると思います。
具体的には下記のようなスクリプトを用意してやれば、font_path
に指定したファイルにどんなフォントが定義されているかを確認することが可能となります。
from PIL import ImageFont
# フォントのパス
font_path = 'Helvetica.ttc'
for i in range(100):
try:
# index=iでフォントオブジェクトを生成してみる
font = ImageFont.truetype(font=font_path, index=i)
except OSError:
# 例外が発生したらindex=iのフォントは存在しないのでループ終了
break
# フォントファミリーとフォントスタイルを出力
print(font.getname())
例えば上記のように font_path
に 'Helvetica.ttc'
を指定した場合、スクリプトを実行して出力される結果は下記のようになります。
('Helvetica', 'Regular') ('Helvetica', 'Bold') ('Helvetica', 'Oblique') ('Helvetica', 'Bold Oblique') ('Helvetica', 'Light') ('Helvetica', 'Light Oblique')
この結果より、Helvetica.ttc
には6種類のスタイルが定義されていることが確認できます。Regular が標準、Bold が太字、Oblique が斜体、Light が細字を意味しますので、例えば太字のスタイルで描画したいのであれば index=1
を、細字&斜体のスタイルで描画したいのであれば index=5
を指定して ImageFont.truetype
関数を実行してやれば良いことになります。
実際に、Helvetica の太字と細字&斜体のスタイルで描画を行うスクリプトの例が下記となります。
from PIL import Image, ImageDraw, ImageFont
# 使用するフォント
font_name = 'Helvetica.ttc'
# 描画する文字列
msg = 'Hello!'
# Imageオブジェクトの生成
image = Image.new('RGB', (200, 100), 'lightgray')
# Drawオブジェクトの生成
drawer = ImageDraw.Draw(image)
# 太字で描画
font = ImageFont.truetype(font=font_name, index=1)
drawer.text(xy=(20, 20), text=msg, fill='black', font=font)
# 細字&斜体で描画
font = ImageFont.truetype(font=font_name, index=5)
drawer.text(xy=(20, 60), text=msg, fill='black', font=font)
# 文字列描画後の画像を表示
image.show()
実行すれば Hello!
という文字列が2つ描画されている画像が表示されるはずです。そして、それぞれの文字列が太字・細字&斜体のスタイルで描画されていることが確認できると思います。ちょっとサイズが小さくて分かりにくいかも…。
前述でも説明しましたが、定義されているスタイルの種類はフォント(のファイル)によって異なるので注意してください。例えば Menlo
の場合は、下記の4つしかスタイルが定義されていません(さらに斜体が Italic で表現されています)。
('Menlo', 'Regular') ('Menlo', 'Bold') ('Menlo', 'Italic') ('Menlo', 'Bold Italic')
また、フォント(のファイル)によってはスタイル毎にファイルが別れている場合があります。例えば Mac には Times New Roman のフォントのファイルが下記のように複数用意されており、スタイル毎にファイルが別れていることが確認できます。
Times New Roman Bold Italic.ttf Times New Roman Bold.ttf Times New Roman Italic.ttf Times New Roman.ttf
こういった背景より、スタイルを適切に使い分けるようにするためには、事前に前述で示したようなスクリプトでフォントのファイルで定義されているスタイルを調べておいた方が良いと思います。
フォントのサイズの変更
続いてフォントのサイズの変更方法について説明してきます。
ちょっとここまでの話は複雑だったかもしれませんが、フォントのサイズの変更に関しては単純明快です。
スポンサーリンク
ImageFont.truetype
関数の size
引数で指定
フォントのサイズの変更に関しては2つの方法を紹介していきます。1つ目が、ImageFont.truetype
を実行する際に size
引数を指定する方法になります。要は、フォントオブジェクトを生成する際にフォントのサイズを指定します。size
引数にはピクセル数を整数で指定します。
これにより、そのフォントオブジェクトを font
引数に指定して text
メソッドを実行してやれば、size
引数で指定したサイズの文字が描画されることになります。size
引数のデフォルト値は 10
になりますので、より大きな文字を描画したいのであれば 10
よりも大きい整数を指定してやれば良いことになります。
例えば下記を実行すればフォントサイズ 20
とフォントサイズ 40
とで文字列を描画した結果が表示されることになります(前者は太字、後者は細字&斜体のスタイルを適用しています)。
from PIL import Image, ImageDraw, ImageFont
# 使用するフォント
font_name = 'Helvetica.ttc'
# 描画する文字列
msg = 'Hello!'
# Imageオブジェクトの生成
image = Image.new('RGB', (200, 100), 'lightgray')
# Drawオブジェクトの生成
drawer = ImageDraw.Draw(image)
# サイズ20・太字で描画
font = ImageFont.truetype(font=font_name, size=20, index=1)
drawer.text(xy=(20, 20), text=msg, fill='black', font=font)
# サイズ40・細字&斜体で描画
font = ImageFont.truetype(font=font_name, size=40, index=5)
drawer.text(xy=(20, 60), text=msg, fill='black', font=font)
# 文字列描画後の画像を表示
image.show()
このスクリプトを実行して表示される画像は下の図のようなものになります。上側の文字列はフォントサイズ 20
で、下側の文字列のフォントサイズ 40
で描画しており、文字の大きさが異なることが確認できると思います。
text
メソッドの font_size
引数で指定
ここまで説明してきたように、ImageFont.truetype
関数でフォントオブジェクトを生成することによって描画する文字列のフォントやスタイル、さらにはサイズ等を指定することが可能となります。
まぁでも、フォントオブジェクトを生成するのは面倒ですし、何より font
引数に指定可能なパスを自分で調べる必要があって手順が複雑です。
そんな方に朗報です。最新の Pillow (バージョン 10.1.0 以降) であれば、フォントのサイズの変更はフォントオブジェクトの生成なしに実現可能です。続いては、フォントオブジェクトの生成を行わずにフォントのサイズを変更する方法について説明します。
手順は簡単で、text
メソッド実行時に font_size
引数を指定してやれば良いだけになります。font_size
引数には整数を指定します。この際には、フォントとしてはデフォルト設定のものが使用されることになります。
例えば下記を実行すればフォントサイズ 20
とフォントサイズ 40
とで文字列を描画した結果が表示されることになります。
from PIL import Image, ImageDraw
# 描画する文字列
msg = 'Hello!'
# Imageオブジェクトの生成
image = Image.new('RGB', (200, 100), 'lightgray')
# Drawオブジェクトの生成
drawer = ImageDraw.Draw(image)
# サイズ20で描画
drawer.text(xy=(20, 20), text=msg, fill='black', font_size=20)
# サイズ40・細字&斜体で描画
drawer.text(xy=(20, 50), text=msg, fill='black', font_size=40)
# 文字列描画後の画像を表示
image.show()
このスクリプトを実行して表示される画像は下の図のようなものになります。上側の文字列はフォントサイズ 20
で、下側の文字列のフォントサイズ 40
で描画しており、text
メソッドの引数でも文字の大きさを変更できることが確認できると思います。
こんな感じで、フォントのサイズを変更したいだけであれば text
メソッドの引数指定のみで実現することが可能です。この方法は、フォントオブジェクトを生成しなくて良いので、とにかく文字を大きくしたい場合などに活躍すると思います。それに対し、フォントやスタイルも指定したい場合はフォントオブジェクトを生成する方法を採用する必要があります。
また、text
メソッドに font
引数を指定した場合、font_size
引数の指定は無視されるようになるので注意してください。font
引数を指定した場合は、font
引数に指定したフォントオブジェクトに設定されたフォントのサイズが優先されることになります。フォントオブジェクト生成時に size
引数を指定しなかったのであれば、デフォルト値の 10
のサイズが優先されることになります。
この辺りを頭に入れて、文字のサイズ変更の2つの方法を適切に使い分けていただければと思います!
まとめ
このページでは、Python の画像処理ライブラリの1つである Pillow のフォントについて説明しました!
Pillow では ImageDraw モジュールにおける Draw
クラスの text
メソッドにより画像に文字列を描画することが可能です。そして、その文字列のフォントやスタイル、さらにはサイズは text
メソッドの font
引数の指定により変更することができます。
この font
引数にはフォントオブジェクトを指定する必要があり、このフォントオブジェクトは Pillow の ImageFont モジュールにおける truetype
関数から生成することができます。このフォントオブジェクト生成時にフォントやスタイル、さらにサイズを指定することで自由自在に描画する文字列のフォントを変更することができます。が、特に truetype
関数の font
引数(第1引数)に指定可能なパスが OS によって異なる点に注意してください。
また、サイズのみを変更するのであれば、フォントオブジェクトを用意する必要もなく、text
メソッドの font_size
引数の指定で変更することが可能です。デフォルトのフォントのサイズが小さいので、とにかく大きい文字を描画したいのであれば text
メソッドの font_size
の指定のみで十分だと思います。最新の Pillow であれば、この方法でのフォントサイズの変更が可能ですので、是非このサイズ変更についても覚えておいてください!