問題の再現
.NETのGraphics.MeasureStringメソッドを利用すると文字列のサイズを測定できますが、通常の方法での測定結果に少しずれが発生します。ここでは正確の測定結果を得る方法を説明します。
まずテスト環境を作成します。新しいWindows Formプロジェクトを作成し、Formのコードを以下のように準備します。(Form7をForm1に変更してください)
public partial class Form7 : Form
{
public Form7()
{
InitializeComponent();
Font = new Font(Font.FontFamily, 14);
Size = new Size(300, 250);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e); var g = e.Graphics;
var str = "文字列を測定する";
// ----ここはテストコード----
}
}
まず方法1:通常の方法で文字列を測定します。
// method 1: Normal string measure g.DrawString(str, this.Font, Brushes.Black, 50, 50); var size = g.MeasureString(str, this.Font); g.DrawRectangle(Pens.Red, 50, 50, size.Width, size.Height);
テストコードを一番上のFormのコードの「—-ここはテストコード—-」のところに差し替えてください。プログラムを実行すると、文字列と測定結果の枠を一緒に画面に表示し、結果は下図の通りです。

この図による、文字列の印刷位置とサイズの測定結果共にずれが発生することわかります。
解決案
次に方法2:StringFormatを利用し文字列を測定します。
// method 2: measure string with StringFormat
using (StringFormat sf = new StringFormat(StringFormat.GenericTypographic))
{
g.DrawString(str, this.Font, Brushes.Black, 50, 100, sf);
var size2 = g.MeasureString(str, this.Font, this.Width, sf);
g.DrawRectangle(Pens.Blue, 50, 100, size2.Width, size2.Height);
}
結果を確認すると、文字列の位置と測定結果共に正しく表示しています。

キーはStringFormatを利用し、StringFormatのインスタンスを作成する際にStringFormat.GenericTypographicを指定することです。
(最終更新:2018/11/19)