PILを使用する場合、テキストを中央揃え(および中央垂直揃え)にするにはどうすればよいですか?
使用する - Draw.textsize
method テキストサイズを計算し、それに応じて位置を再計算します。
以下に例を示します。
from PIL import Image, ImageDraw
W, H = (300,200)
msg = "hello"
im = Image.new("RGBA",(W,H),"yellow")
draw = ImageDraw.Draw(im)
w, h = draw.textsize(msg)
draw.text(((W-w)/2,(H-h)/2), msg, fill="black")
im.save("hello.png", "PNG")
そして結果:
フォントサイズが異なる場合は、次のようなフォントを含めます。
myFont = ImageFont.truetype("my-font.ttf", 16)
draw.textsize(msg, font=myFont)
次に、textwrapを使用して長い行を断片に分割し、textsize
メソッドを使用して位置を計算するコード例を示します。
from PIL import Image, ImageDraw, ImageFont
import textwrap
astr = '''The rain in Spain falls mainly on the plains.'''
para = textwrap.wrap(astr, width=15)
MAX_W, MAX_H = 200, 200
im = Image.new('RGB', (MAX_W, MAX_H), (0, 0, 0, 0))
draw = ImageDraw.Draw(im)
font = ImageFont.truetype(
'/usr/share/fonts/truetype/msttcorefonts/Arial.ttf', 18)
current_h, pad = 50, 10
for line in para:
w, h = draw.textsize(line, font=font)
draw.text(((MAX_W - w) / 2, current_h), line, font=font)
current_h += h + pad
im.save('test.png')
Draw.textsizeメソッドは不正確であることに注意してください。私は低ピクセルの画像を扱っていましたが、いくつかのテストの後、textsizeではすべての文字が6ピクセル幅であると見なされますが、「I」では最大になります。 2ピクセルと「W」は最小かかります。 8ピクセル(私の場合)。そして、私のテキストに応じて、それはまったく中央に置かれた、またはまったく置かれなかった。とはいえ、「6」は平均だったと思うので、長いテキストや大きな画像を扱っているのであれば、それでも大丈夫でしょう。
しかし、今、本当の精度が必要な場合は、使用するフォントオブジェクトのgetsizeメソッドを使用する方が適切です。
arial = ImageFont.truetype("arial.ttf", 9)
w,h = arial.getsize(msg)
draw.text(((W-w)/2,(H-h)/2), msg, font=arial, fill="black")
Edilioのリンクで使用されているとおり。
この実装は http://tools.jedutils.com/tools/center-text-image で見つけることができます
自分でルーチンを実装する代わりに、そのページを使用してすぐにイメージを作成できますが、使用されるコードもページに含まれています。
ImageDraw.textのPILドキュメント は開始するのに適した場所ですが、質問には答えないでください。
以下は、画像の中央ではなく、任意の境界ボックスでテキストを中央に配置する方法の例です。境界ボックスは次のように定義されます:(x1, y1)
=左上隅と(x2, y2)
=右下隅。
from PIL import Image, ImageDraw, ImageFont
# Create blank rectangle to write on
image = Image.new('RGB', (300, 300), (63, 63, 63, 0))
draw = ImageDraw.Draw(image)
message = 'Stuck in\nthe middle\nwith you'
bounding_box = [20, 30, 110, 160]
x1, y1, x2, y2 = bounding_box # For easy reading
font = ImageFont.truetype('Consolas.ttf', size=12)
# Calculate the width and height of the text to be drawn, given font size
w, h = draw.textsize(message, font=font)
# Calculate the mid points and offset by the upper left corner of the bounding box
x = (x2 - x1 - w)/2 + x1
y = (y2 - y1 - h)/2 + y1
# Write the text to the image, where (x,y) is the top left corner of the text
draw.text((x, y), message, align='center', font=font)
# Draw the bounding box to show that this works
draw.rectangle([x1, y1, x2, y2])
image.show()
image.save('text_center_multiline.png')
出力は、境界ボックスのテキストを垂直方向および水平方向の中央に表示します 。
PILがalign='center'
パラメータ。ただし、複数行テキストのみ用です。メッセージが1行の場合、手動で中央揃えする必要があります。メッセージが複数行の場合、align='center'
は後続の行で作業を行いますが、テキストブロックを手動で中央に配置する必要があります。これらのケースは両方とも、上記のコードで一度に解決されます。
textsize
メソッド( docs を参照)を使用して、実際に描画する前にテキストオブジェクトの寸法を把握します。次に、適切な座標から開始して描画します。