web-dev-qa-db-ja.com

テキストの幅の測定(Python / PIL)

次の2つの方法を使用して、設定されたフォントタイプとサイズのサンプル文字列のレンダリングwidthを計算します。

font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 14)
sample = "Lorem ipsum dolor sit amet, partem periculis an duo, eum lorem paulo an, mazim feugiat lobortis sea ut. In est error eirmod vituperata, prima iudicabit rationibus mel et. Paulo accumsan ad sit, et modus assueverit eum. Quod homero adversarium vel ne, mel noster dolorum te, qui ea senserit argumentum complectitur. Duo at laudem explicari deterruisset, eu quo hinc mnesarchum. Vel autem insolens atomorum at, dolorum suavitate voluptatum duo ex."
#METHOD 1
draw_txt = ImageDraw.Draw(img)
width, height = draw_txt.textsize(sample, font=font)
print width
#METHOD 2
width = 0
for c in sample:
    width += font.getsize(c)[0]
print width

METHOD 13236の幅を生成しますが、METHOD 23270を生成します。なぜ矛盾があるのですか?さらに、サンプルテキストが短いほど、これら2つの方法の不一致が小さくなることにも気付きました。

フードの下で何が起こっているのですか?そして、どの幅は、レンダリングされた文のtrue幅と考えることができますか?最後に、両方のメソッドがほぼ同じ幅をレポートするようにするためのTweakはありますか?

注:サンプルテキストは445文字です

11
Hassan Baig

字詰め

ここでは2つの異なることを行っています。

  • 長いテキストの幅を見つけます。
  • すべての文字の幅を見つけ、盲目的にそれらを一緒に追加します

モノスペースフォントを使用している場合、状況は異なる可能性がありますが、フォントは一般にkerningと呼ばれるものを使用して、テキストを滑らかにし、少しきつめにします。

Wikipedia さんのコメント:

タイポグラフィでは、kerningはプロポーショナルフォントの文字間の間隔を調整するプロセスであり、通常は視覚的に満足のいく結果が得られます。カーニングは個々の文字フォーム間のスペースを調整し、トラッキング(文字間隔)は文字の範囲にわたって間隔を均一に調整します。適切にカーニングされたフォントでは、文字の各ペア間の2次元の空白スペースはすべて、視覚的に類似した領域を持っています。

Kerning brings A and V closer with their serifs over each other

これが DejaVuSansフォントのカーニング です。

font kerning showing different char widths

フードの下

内部的には、Pillowは2つの方法で大きな違いはありません。それはあなたが彼らを異なる方法で呼んでいるだけです。

3番目のメソッドを追加して、メソッド2と同じ関数を使用して文全体の幅を取得すると、メソッド1と同じように文全体を取得する場合と同じ幅が得られます。

# METHOD 3
width = font.getsize(sample)[0]
print width

これが枕の ImageDraw.textsize (メソッド1と3から)です。

def textsize(self, text, font=None, *args, **kwargs):
    """Get the size of a given string, in pixels."""
    if self._multiline_check(text):
        return self.multiline_textsize(text, font, *args, **kwargs)

    if font is None:
        font = self.getfont()
    return font.getsize(text)

1行のテキストの場合、これはfont.getsizeを返すだけであり、メソッド2と同じです。 (また、複数行のテキストの場合、テキストを行に分割し、いくつかのfont.getsize呼び出しの合計を返します。)

17
Hugo