PILでTrueType日本語フォントを使う

PIL(Python Image Libraly)で日本語フォント使おうとすると、ラスタライズ結果がぐちゃぐちゃになることがある。これはハマった。

つぶれる条件はどうやら、ビットマップを持つフォントのビットマップが適用される場合のようだ。ビットマップが適用されないぐらい十分大きいサイズで描いて、それを目的のサイズに縮小して問題を回避。アンチエイリアスされた文字を得るのが目的ならこれでOK。

import Image, ImageFont, ImageDraw

def imaged_text(text, fontfile, fontsize, color, scale_bias=4):
    font = ImageFont.truetype(fontfile, fontsize * scale_bias)
    image = Image.new('RGBA', (1, 1))
    draw = ImageDraw.Draw(image)
    w,h = draw.textsize(text, font=font)
    del draw
    image = Image.new('RGBA', (w, h))
    draw = ImageDraw.Draw(image)
    draw.text((0, 0), text, font=font, fill=color)
    del draw
    return image.resize((w / scale_bias, h / scale_bias), Image.ANTIALIAS)

def draw_text_to(target, position, text, fontfile, fontsize, color):
    image = imaged_text(text, fontfile, fontsize, color)
    target.paste(image , position, image)

#IPA Pゴシックで「こんにちは世界」と書く
image = Image.open('source.png')
draw_text_to(image, (0, 0), u"こんにちは世界", 'ipagp.ttf', 16, '#FFF')
image.save('output.png')

コスト度外視のコード(w

シャキッとしたビットマップが欲しい場合、明示的にBDFフォントを使ったほうがいいはず…なんだけど、PILはビットマップフォントを256文字しか想定していない模様。別の方法が必要かな。

TrueTypeに埋め込まれたビットマップフォントをBDFに似た形式で抽出するコードを書いておられる方がいます。

http://hp.vector.co.jp/authors/VA013241/font/sbitget.html

どうにか使いもんにならないかな。