1

我现在面临一个问题,即获取一个适合提供的像素宽度的字符串。

例如,如果我有这样的句子(在 JavaScript 中):

var mystring = "This is my sentence, I need to get just 50 pixels from it."

如果我MeasureString在 C# 中使用该方法,我可以获得宽度:

Font font = new Font("Segoe UI", 11, FontStyle.Regular, GraphicsUnit.Point);
SizeF size = graphics.MeasureString(mystring, font);

假设这个字符串的宽度是 400 像素,但我可以在网站上显示的最大宽度是 50 像素。

如果我缩短字符串并测量它直到它小于 50px 宽度它可以工作,但它需要多次迭代,这根本不是一个好的解决方案

有没有人对此有很好的解决方案?

谢谢。

4

5 回答 5

1
string myString = "This is my sentence, I need to get just 50 pixels from it."
Font font = new Font("Segoe UI", 11, FontStyle.Regular, GraphicsUnit.Point); 

int desiredWidth = 50;
int myStringWidth = TextRenderer.MeasureText(myString , font).Width;
string result = mystring.Substring(0, myString.Length * desiredWidth / myStringWidth);

此解决方案不考虑换行符。

于 2011-03-14T07:43:29.113 回答
1

我想添加到本节 - “如果我缩短字符串并测量它直到它小于 50px 宽度......”

为什么不从字符串的中间开始进行二进制搜索。这是初学者的位置。无论字符串有多长 - 找出理想长度所需的时间要少得多。复杂度从 n 降低到 log(n)。

为了获得更好的结果,如果字符串真的很长,例如 500 个字符,您可以在开始二进制搜索之前截断它。

于 2009-07-22T09:08:11.167 回答
1

对最佳长度使用二分搜索不需要多次迭代。鉴于文本渲染的复杂性,我相信这是你能做的最好的。您不能只为每个字符取一个宽度并将它们加在一起。

于 2009-07-22T07:00:53.560 回答
0

您可以将字符串的宽度近似为子字符串的宽度之和。如果您的子字符串以空格为界†,它甚至可能是一个非常好的近似值。但是,除非您询问任何特定字符串的确切宽度,否则您无法知道,因为文本渲染引擎会执行诸如字距调整(改变字符之间的间距)之类的事情。

†并且您可能希望它们至少在欧洲语言中是这样,因为阅读仅在空白处断开的文本比在中间词中断开的文本要容易得多,即使它导致文本看起来稍微有些粗糙。

于 2009-07-22T07:03:09.937 回答
0

StringBoxer 类的 GetBoxedString 方法“估计”可以放入矩形并返回的字符串数量(空格分隔的单词、Enter 分隔的单词甚至长字符)(复制/粘贴时要小心,因为我不能将整个代码放入下面的灰色框中):

公共密封类 StringBoxer {

public string GetBoxedString(string s, Size size, Font font)
{

  int longestStringLengthInWidth = 0;
  var result = string.Empty;
  if (size.Height < font.Height)
  {
    return string.Empty;
  }

  using (var bmp = new Bitmap(size.Width, size.Height))
  {
    int index = 0;
    var words = this.SplitString(s);


    var measuredSizeBeforeAddingWord = new SizeF(0, 0);

    using (var graphic = Graphics.FromImage(bmp))
    {
      longestStringLengthInWidth = CalculateLongestStringLength(size, font);

      do
      {
        if (words[index].Length > longestStringLengthInWidth)
        {
          //// If a word is longer than the maximum string length for the specified size then break it into characters and add char 0 at the begining of each of those characters
          var brokenCharacters = words[index].Select(c => ((char)0) + c.ToString()).ToList();
          brokenCharacters.Add(" ");
          words.RemoveAt(index);
          words.InsertRange(index, brokenCharacters);
        }

        var measuredSizeAfterAddingWord = graphic.MeasureString(result + (!words[index].EndsWith("\n") ? words[index] + " " : words[index]), font, size);
        if ((words[index].Contains('\n') || measuredSizeAfterAddingWord == measuredSizeBeforeAddingWord) && measuredSizeAfterAddingWord.Height >= size.Height-font.Height)
        {
          return result.TrimEnd();
        }

        measuredSizeBeforeAddingWord = measuredSizeAfterAddingWord;

        if (words[index].Contains((char)0))
        {
          result += words[index].Replace(((char)0).ToString(), string.Empty);
        }
        else
        {
          result += (!words[index].EndsWith("\n") ? words[index] + " " : words[index]);
        }

        index++;
      }
      while (index < words.Count);
    }
  }

  return result.TrimEnd();
}

private List<string> SplitString(string s)
{
  var words = s.Split(' ').ToList();
  var index = 0;
  do
  {
    // If a word contains Enter key(s) then break it into more words and replace them with the original word.
    if (!words[index].Contains("\n"))
    {
      index++;
      continue;
    }

    var enterSplitWords = (words[index] + " ").Split('\n');
    var brokenWords = enterSplitWords.Select(str => (enterSplitWords.LastOrDefault() != str ? str + "\n" : str).Replace(" ", string.Empty)).ToList();
    words.RemoveAt(index);
    words.InsertRange(index, brokenWords);
    index += brokenWords.Count;
  }
  while (index < words.Count);

  return words;
}

private static int CalculateLongestStringLength(Size size, Font font)
{
  var tempString = string.Empty;
  var longestStringLengthInWidth = 0;
  using (var bmp = new Bitmap(size.Width, size.Height))
  {
    using (var graphic = Graphics.FromImage(bmp))
    {
      do
      {
        if (Math.Floor(graphic.MeasureString(tempString, font, size).Height) <= font.Height)
        {
          longestStringLengthInWidth++;
        }
        else
        {
          break;
        }

        tempString += "x";
      } while (true);
    }
  }

  return longestStringLengthInWidth;
}

}

于 2017-05-21T11:05:36.193 回答