【问题标题】:how to measure width of a string precisely?如何精确测量字符串的宽度?
【发布时间】:2012-07-29 10:48:38
【问题描述】:

首先,问题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 如何计算绘图区域的大小?肯定是其他函数,因为大小总是不同的。

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

【问题讨论】:

标签: c# winforms gdi+


【解决方案1】:

您只需要消除额外的宽度。您可以使用string format

GdipStringFormatGetGenericTypographic()

你也可以使用:

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

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

On 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);
}

【讨论】:

  • 它似乎可以工作,直到我发现一些格式问题,当我修复它时,整个函数刚刚开始返回与 MeasureString 相同的错误值...
  • 工作得很好......唯一的解决方法是该行:format.SetMeasurableCharacterRanges(new CharacterRange[] { range });
【解决方案2】:

我在这里参加聚会有点晚了,但我试图做类似的事情并偶然发现了这个问题。您可能已经看到the documentation for the Graphics.MeasureString method on MSDN 的以下评论:

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

您似乎试图遵循此建议,因为您使用StringFormat.GenericTypographic 作为自定义StringFormat 对象的起点。但是,这条线

format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

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

format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;

【讨论】:

    【解决方案3】:

    尝试使用以下方法:

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

    它也可能对您有所帮助:

    编写自定义度量方法:

    • 在特殊字符上拆分条目字符串
    • 使用上述 .net 方法
    • 计算特殊字符的宽度并求和...

    Read Ian Boyd answer

    【讨论】:

      【解决方案4】:

      使用 Graphics.MeasureCharacterRanges 的方法返回包含字符串中每个单独字母的所有矩形及其位置:Measure character positions when drawing long strings in C#

      我已经使用了该帖子中的 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;
          }
      }
      

      请注意,矩形的高度是字体的高度,而不是字符本身的高度。如果您需要身高,请查看此帖子:Determining exact glyph height in specified font

      最后一点:我使用 MeasureCharacterRanges 的原因是因为我尝试的所有其他方法都未能给我一个边界框,文本的左右两侧没有空格。这篇文章The wonders of text rendering and GDI 提供了一种获取字符串宽度并使用 TextRenderer 删除此空间的方法,因此整个事情可以在大约两行代码中完成。我还没有检查结果。

      【讨论】:

        猜你喜欢
        • 2012-04-15
        • 2021-10-09
        • 1970-01-01
        • 2010-11-28
        • 1970-01-01
        • 1970-01-01
        • 2010-10-29
        • 2020-04-22
        • 2021-11-10
        相关资源
        最近更新 更多