如何精确测量弦的宽度?

首先,问题How to measure width of character precisely? 得到回答, 对这种情况并没有多大帮助,所以这不是重复的

我有一个字符串。 我使用graphics.DrawString绘制,但是当我需要在它之后添加另一个时,我需要知道前一个字符串的精确宽度。

为此,我使用graphics.MeasureString:

 StringFormat format = new StringFormat(StringFormat.GenericTypographic); format.Alignment = StringAlignment.Center; format.Trimming = StringTrimming.None; format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces; 

我已经尝试了许多其他函数,就像TextRendered.MeasureText但是所有函数都失败了,并且所有可能的参数组合都是如此。

MeasureString的上述组合最接近我的需要(它在大多数情况下都适用,特殊字符除外),但是使用像#破坏它这样的字符。 宽度更短或更长。

有没有办法获得DrawString函数生成的文本的精确大小? DrawString如何计算绘图区域的大小? 它必须是一些其他function,因为尺寸总是不同的。

整个应用程序的源代码在这里https://gitorious.org/pidgeon/pidgeon-main/ (我使用它的文件,是https://gitorious.org/pidgeon/pidgeon-main/blobs/master/scrollback /SBABox.cs )

你只需要消除额外的宽度。 您可以使用字符串格式执行此操作:

 GdipStringFormatGetGenericTypographic() 

你也可以使用:

 float doubleWidth = g.MeasureString(text+text,...).Width; float singleWidth = g.MeasureString(text).Width; float textWidth = doubleWidth-singleWidth; 

这将允许您使用其他语言,如日语

在codeproject上 ,Pierre Anaud的解决方案是使用MeasureCharacterRanges ,它返回一个与指定字符串的边界框完全匹配的区域:

 static public int MeasureDisplayStringWidth(Graphics graphics, string text, Font font) { System.Drawing.StringFormat format = new System.Drawing.StringFormat (); System.Drawing.RectangleF rect = new System.Drawing.RectangleF(0, 0, 1000, 1000); var ranges = new System.Drawing.CharacterRange(0, text.Length); System.Drawing.Region[] regions = new System.Drawing.Region[1]; format.SetMeasurableCharacterRanges (ranges); regions = graphics.MeasureCharacterRanges (text, font, rect, format); rect = regions[0].GetBounds (graphics); return (int)(rect.Right + 1.0f); } 

我在这里参加派对有点晚了,但是我试图做类似的事情,偶然发现了这个问题。 您可能已经在MSDN上的Graphics.MeasureString方法的文档中看到了以下注释:

MeasureString方法设计用于单个字符串,并在字符串之前和之后包含少量额外空格以允许悬垂字形。 此外, DrawString方法调整字形点以优化显示质量,并且可能显示比MeasureString报告的字符串更窄的字符串。 要获取适合布局中相邻字符串的度量(例如,在实现格式化文本时),请使用MeasureCharacterRanges方法或采用StringFormat的MeasureString方法之一,并传递GenericTypographic 。 另外,确保Graphics的TextRenderingHint是AntiAlias 。

您似乎正在尝试遵循此建议,因为您使用StringFormat.GenericTypographic作为自定义StringFormat对象的起点。 但是,行

 format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces; 

有效地否定了你开始使用StringFormat.GenericTypographic的事实,因为它清除了之前设置的任何标志。 您可能要做的是设置StringFormatFlags.MeasureTrailingSpaces标志,同时保留其他标志,如下所示:

 format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; 

尝试使用此方法:

 GDI+ (graphics.MeasureString and graphics.DrawString) >> System.Drawing.Graphics GDI (TextRenderer.MeasureText and TextRenderer.DrawText) 

它也可以帮助你:

编写自定义度量方法:

  • 拆分特殊字符的条目字符串
  • 使用上面的.net方法
  • 计算特殊字符的宽度和总和…

阅读Ian Boyd的回答

使用Graphics.MeasureCharacterRanges返回包含字符串中每个单独字母的所有矩形的方法,这里给出它们的位置: 在C#中绘制长字符串时测量字符位置

我已经使用了该post中的MeasureCharactersInWord和MeasureCharacters方法,然后为了找到确切的宽度而没有在字符串的每一边添加空格,我使用以下代码:

 var w = 0F; var rects = MeasureCharacters(Graphics.FromHwnd(IntPtr.Zero), font, text); if (rects.Count>0) { if (rects.Count == 1) { w = rects.First().Width; } else { var r0 = rects.First(); var rN = rects.Last(); w = rN.X - r0.X + rN.Width; } } 

请注意,矩形的高度是字体的高度,而不是字符本身的高度。 如果你需要高度检查这篇文章: 确定指定字体的确切字形高度

最后一点:我使用MeasureCharacterRanges的原因是因为我尝试的所有其他方法都没有给我一个没有空格的边界框到文本的左边和右边。 这篇文章文本渲染和GDI的奇迹提供了一种获取字符串宽度并使用TextRenderer删除此空间的方法,因此整个过程可以在大约两行代码中完成。 我没有检查过结果。