2011年8月25日木曜日

文字列を中央に描画する

文字列を中央に描画...がうまくできなかった話


どうも。
いち、プログラマのyu1rowです。

例えば画像の中央に文字列を描画したい場合、java.awt.FontMetricsクラスを用いて、文字列が描画されたときの全体のサイズを取得して実現できます。
しかし、これで取得した領域で計算すると、文字がちょっと上にずれます。というか、ずれて見えます。
これは文字列の「ベースライン」を考慮していないからのようです。

とある四角形を、とある領域の真ん中に描きたい場合、描画開始位置の計算は、普通は以下のようになります。
  • x = ( 領域の幅   - 四角形の幅   ) / 2;
  • y = ( 領域の高さ - 四角形の高さ ) / 2;
しかし、java.awt.Graphics.drawString()は「ベースライン」を描画開始位置に合わせてしまいますので、y座標を補正する必要があります。
方法は、ベースラインから文字の上端までの距離をy座標に足すだけで、距離の取得はFontMetrics.getMaxAscent()を使用します。

補正後の描画開始位置の計算は、以下の通り。
  • x = ( 領域の幅   - 四角形の幅   ) / 2;
  • y = ( 領域の高さ - 四角形の高さ ) / 2 + FontMetrics.getMaxAscent();

御託は置いといて


はい、ソースどーん!
package com.yu1row.blog;

import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Practice01 {

    public static void main(String[] args) throws IOException {
        Rectangle size = new Rectangle(200, 30);
        BufferedImage image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
        drawStringCenter(image.getGraphics(), size, "よろしくお願いしまーす!");
        ImageIO.write(image, "PNG", new File("center.png"));
    }

    public static void drawStringCenter(Graphics g, Rectangle rect, String text) {
        // Calc draw position
        FontMetrics fm = g.getFontMetrics();
        Rectangle rectText = fm.getStringBounds(text, g).getBounds();
        int x = (rect.width - rectText.width) / 2;
        int y = (rect.height - rectText.height) / 2 + fm.getMaxAscent();
        // Draw text
        g.drawString(text, x, y);
    }
}

アラビア文字など、右から左に書かれる文字列がどうなるのかとか、面倒なんで未検証です。

0 件のコメント:

コメントを投稿