Pillow の ImageDraw#textsize() が間違った値を返している件
Pillow 2.2.0 以降には ImageDraw#textsize() にバグがあり、TrueType フォントを指定していると正しい高さが返りません。
どういう問題なのか
テキストとそれを囲む四角を描画する次のコードを実行してみます。
from PIL import Image, ImageDraw, ImageFont image = Image.new('RGB', (512, 256), (255, 255, 255)) drawer = ImageDraw.Draw(image) font = ImageFont.truetype('/Library/Fonts/Osaka.ttf', 32) # drawing text STRING = 'Hello, python language!' drawer.text((10, 10), STRING, fill='black', font=font) # drawing rectangle surrounding text size = drawer.textsize(STRING, font=font) drawer.rectangle((10, 10, 10 + size[0], 10 + size[1]), outline='black') image.save('example.png', 'PNG')
すると次のような図が出力されます。
カンマや y, g と言った文字の下辺が枠の外から飛び出しています。
この問題は TrueType フォントを表す PIL.ImageFont.FreeTypeFont クラスが文字の大きさを返す際に
offset 値を含めないサイズを返してしまっているために発生しています。
この問題はすでに github 上では修正されているのですが、
現在リリースされている Pillow-2.5.1 ではこの問題は解決されていません。
回避策
Pillow-2.2.0 以降には FreeTypeFont クラスに getoffset() というメソッドがあるので、この値を用いて補正します。
どのバージョンの Pillow でも動くようにするには以下のようなコードを書きます*1。
from PIL import PILLOW_VERSION from PIL.ImageFont import FreeTypeFont def textsize(drawer, text, font=None): size = drawer.textsize(text, font) # Avoid offset problem in Pillow (>= 2.2.0, < 2.6.0) if isinstance(font, FreeTypeFont) and "2.2.0" <= PILLOW_VERSION < "2.6.0": offset = font.getoffset(text) size = (size[0] + offset[0], size[1] + offset[1]) return size
まとめ
しばらくはバグったままなので、adhoc なコードを使って回避して生きていきましょう。
懺悔
このバグは日本語フォントが欠ける問題を直したところに、他の人が offset 値の調整を加えることで発生しているので
僕は(間接的ではあるものの)バグの生みの親ということになります。
大変申し訳無いです。
*1:まだ 2.6.0 はリリースされていませんが、次のリリースで直る想定で書かれています