如何测量给定字体/大小(C#)中数字的像素宽度

我正在尝试使用OpenXML规范中的官方公式计算Excel列的像素宽度,如本文所述。 但是,为了应用这个公式,我需要知道Normal字体的最大数字宽度 ,它是最宽数字的像素宽度。 OpenXML规范给出了这个例子作为澄清:

以Calibri字体为例,11磅字体的最大数字宽度为7像素(96 dpi)。

我通过目视检查一个Calibri 11点数字检查这是正确的,它确实是7像素宽。 所以,我正在尝试创建一个方法,它将返回任何字体/大小的最大数字宽度。

我已经按照这个问题提出的建议,但它没有产生我期待的结果。

这是我的测试代码:

var font = new Font("Calibri", 11.0f, FontStyle.Regular); for (var i = 0; i < 10; i++) { Debug.WriteLine(TextRenderer.MeasureText(i.ToString(), font)); } 

这会报告所有数字的宽度均为15。

有什么建议吗?

蒂姆,谢谢

首先让我说我即将展示的代码看起来像一个可怕的黑客,我不是把它作为一个解决方案。 相反,我希望它能更多地揭示MeasureText的行为,它可能会引导您找到最终的解决方案。

我对你的代码做了一些改动。 我正在测量两个下划线字符的长度。 然后,在for循环的主体中,我用两边的下划线测量所需的字符,然后单独减去两个下划线字符的长度。 对于测试场景,我得到7的结果。这个的主要目的是确定MeasureText是否在逐个字符的基础上考虑填充或在字符串的开头/结尾填充。 似乎是后者。 也许这与您收到的其他一些输入相结合,将引导您找到更优雅的解决方案。

 var font = new Font("Calibri", 11.0f, FontStyle.Regular); int underscoreWidth = TextRenderer.MeasureText("__", font).Width; for (var i = 0; i < 10; i++) { int charWidth = TextRenderer.MeasureText(String.Concat("_", i.ToString(), "_"), font).Width - underscoreWidth; Debug.WriteLine(charWidth); } 

TextRenderer并不总是像您期望的那样准确:

来自MSDN: http : //msdn.microsoft.com/en-us/library/8wafk2kt.aspx

例如,TextRenderer的默认行为是将填充添加到绘制文本的边界矩形以容纳悬垂字形

你有Graphics对象或Control对象吗? 如果您正在使用这些,您可以按照预期的方式获得准确的恢复。

看看http://msdn.microsoft.com/en-us/library/6xe5hazb(VS.80).aspx

MeasureText添加填充,虽然它大致与字体大小成线性比例,但数量相当不可预测。 诀窍是减去两个测量值以摆脱填充。 这段代码生成了很开心的数字:

  float size = 5; for (int ix = 0; ix < 10; ++ix) { var font = new Font("Calibri", size, FontStyle.Regular); string txt = new string('0', 100); SizeF sz1 = TextRenderer.MeasureText("00", font) - TextRenderer.MeasureText("0", font); Console.WriteLine("{0} {1:N3}", size, sz1.Width); size += 2; } 

输出:

 5 4.000 7 5.000 9 6.000 11 7.000 13 9.000 15 10.000 17 12.000 19 13.000 21 14.000 23 16.000 

这可以获得你想要的7个像素。 请注意,您必须适应TrueType提示,它可以调整数字的形状,使其主干落在像素边界上。 添加至少一个像素。

测量文字宽度可能是一个nighmare ..我不知道为什么他们这么混乱..

以下是我测量文本长度最准确的方法:

  protected int _MeasureDisplayStringWidth ( Graphics graphics, string text, Font font ) { if ( text == "" ) return 0; StringFormat format = new StringFormat ( StringFormat.GenericDefault ); RectangleF rect = new RectangleF ( 0, 0, 1000, 1000 ); CharacterRange[] ranges = { new CharacterRange ( 0, text.Length ) }; Region[] regions = new Region[1]; format.SetMeasurableCharacterRanges ( ranges ); format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces; regions = graphics.MeasureCharacterRanges ( text, font, rect, format ); rect = regions[0].GetBounds ( graphics ); return (int)( rect.Right ); } 

我不是100%确定这是你真正需要的。

但您可能需要查看此Microsoft页面: