Graphics.MeasureString返回的值不同于Win32 GetTextExtent

时间:2008-10-15 02:59:03

标签: .net winforms dpi highdpi

我一直在尝试在C#中找到一个方法来测量字符串的大小。在Win32中测量字符串的standard method是使用GetTextExtent。真正的目标是找到字体字符的平均宽度和高度。查找字符平均宽度的标准方法是从获取所有字母字符的宽度开始除以52:

size = dc.GetTextExtent(
       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52);
averageWidth = size / 52;

微软有一个页面列出了某些DPI设置下某些字体大小的average character widths,我已经通过自己的GetTextExtent调用确认了它们。

  • Tahoma 8pt,96dpi: 13x6 px
  • Tahoma 9pt,96dpi: 14x7 px
  • Segoe UI 9pt,96dpi :15x7 px

现在我想在.NET WinForms下执行相同的计算。使用Graphics.MeasureString()我想出了代码:

public static SizeF GetAvgCharSizeF(Graphics g, Font font)
{
   String s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

   SizeF textSize = g.MeasureString(s, font);

   float baseUnitX = (textSize.Width / s.Length);
   float baseUnitY = textSize.Height;

   return new SizeF(baseUnitX, baseUnitY);
}

不幸的是,这些值与已知的,可接受的真值不匹配:

  • Tahoma 8pt,96dpi: 14x6 px (14.21x6.09 px)
  • Tahoma 9pt,96dpi: 16x7 px (15.98x6.85 px)
  • Segoe UI 9pt,96dpi: 17x7 px (17.46x6.91 px)

平均字符宽度结果不错,但角色高度太大了约13%。我认为额外的高度是由于高度分类的差异已经改变,包括上升和下降。如果测量字符串测量太高,我尝试将其更改为:

String s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

String s = "acemnorsuvwxyz";

认为现在弦不高,所以测得的高度应该更短。不,它返回完全与包含上升和下降的字符串版本相同的高度(尽管平均宽度略大)。

这可能是什么原因,并且可以获得平均文字高度的平均字符高度,以便它匹配GetTextExtent返回的可接受值?

注意:尽管获取平均字符高度的标准做法是使用GetTextMetrics,但GetTextExtents返回的高度返回相同的值。

1 个答案:

答案 0 :(得分:3)

我怀疑这是因为.NET中的文本呈现引擎不同。您可能想要查找GDI和GDI +之间的差异。如果您调用Application.SetCompatibleTextRenderingDefault(<bool>)方法,并且使用true或false作为参数(我相信默认值为true),事情也可能会再次发生变化。

一般情况下,如果您使用Windows API绘图,则使用Windows API进行测量,如果使用.NET绘图,请使用.NET进行测量。