Каков наилучший способ получить строку, которая соответствует заданной ширине в пикселях? - PullRequest
1 голос
/ 22 июля 2009

Я столкнулся с проблемой получения строки, которая соответствует заданной ширине в пикселях.

Например, если у меня есть такое предложение (в 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 пикселей.

Если я укорачиваю строку и измеряю ее до ширины менее 50 пикселей, это работает, но для этого потребуется много итераций, что не является хорошим решением .

У кого-нибудь есть хорошее решение для этого?

Спасибо.

Ответы [ 5 ]

1 голос
/ 14 марта 2011
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);

Это решение не учитывает разрывы строк.

1 голос
/ 22 июля 2009

Я хотел бы добавить к этому разделу - «Если я укороту строку и измерим ее до ширины менее 50 пикселей ...»

Почему бы вам не выполнить бинарный поиск, начиная с середины строки. Вот местоположение для начинающих. Независимо от того, какова длина строки - потребуется гораздо меньше времени, чтобы выяснить, какова ваша идеальная длина. Сложность сводится к log (n) от n.

Для получения лучших результатов вы можете обрезать строку, если она действительно длинная, например, до 500 символов, перед началом двоичного поиска.

1 голос
/ 22 июля 2009

Использование бинарного поиска оптимальной длины не должно занимать много итераций. Учитывая тонкости рендеринга текста, я считаю, что это лучшее, что вы можете сделать. Вы не можете просто взять ширину для каждого символа и сложить их вместе.

0 голосов
/ 21 мая 2017

Метод GetBoxedString класса StringBoxer «оценивает» количество строк (разделенных пробелами слов, слов, разделенных вводом или даже длинных символов), которые вы можете поместить в прямоугольник и вернуть его (будьте осторожны при копировании / вставке, потому что я не могу вместить весь мой код в серое поле ниже):

публичный закрытый класс 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;
}

}

0 голосов
/ 22 июля 2009

Вы можете приблизительно определить ширину строки как сумму ширины подстрок. Если ваши подстроки ограничены пробелом † это может быть даже довольно хорошим приближением. Но вы не можете знать, пока не спросите точно , какова будет ширина какой-либо конкретной строки, потому что механизм визуализации текста выполняет такие вещи, как кернинг (изменяя расстояние между символами).

† и вы, вероятно, хотите, чтобы они были, по крайней мере, на европейском языке, потому что текст, разбитый только на пробел, намного проще, чем текст, разбитый на середине слова, даже если в результате текст выглядит немного более рваным.

...