获取适合所提供宽度(以像素为单位)的字符串的最佳方法是什么?

发布于 2024-07-28 23:33:51 字数 568 浏览 8 评论 0原文

我现在面临着获取适合所提供宽度(以像素为单位)的字符串的问题。

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

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

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

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

假设该字符串的宽度为 400px,但最大宽度为 I可以在网站上显示的是50px。

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

有人对此有好的解决方案吗?

谢谢。

I am now facing a problem with getting a string that fits the provided width in pixels.

For example, if I have a sentence like this (in JavaScript):

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

If I use the MeasureString method in C# I can get the width:

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

Let's say the width of this string is 400px but the max width I can display on the site is 50px.

If I shorten the string and measure it until it's less than 50px width it works, but it will require many iterations which is not a good solution at all.

Does anyone have a good solution for this?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

清晰传感 2024-08-04 23:33:51

使用二分搜索来获得最佳长度,不应该需要多次迭代。 考虑到文本渲染的复杂性,我相信这是您能做的最好的事情。 您不能只获取每个字符的宽度并将它们加在一起。

Using a binary search for the optimal length it shouldn't take many iterations. Given the intricacies of text rendering, I believe that's the best you can do. You can't just take a width for each char and add them together.

゛清羽墨安 2024-08-04 23:33:51

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

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

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

I would like to add to this section - "If I shorten the string and measure it until it's less than 50px width ..."

Why don't you do a binary search starting from the middle of the string. Here's the location for starters. No matter how long the string is - it will take much lesser time to find out what's your ideal length. The complexity reduces to log(n) from n.

For better results, you can truncate your string if it's really long, like 500 characters, for example, before starting your binary search.

一个人练习一个人 2024-08-04 23:33:51
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);

该解决方案不考虑换行。

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

This solution does not consider line breaks.

合约呢 2024-08-04 23:33:51

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

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

You can approximate the width of a string as being the sum of the width of sub-strings. If your substrings are bounded by whitespace† it may even be a pretty good approximation. But you can't know until you ask exactly how wide any particular string will be, because the text rendering engine does things like kerning (altering the spacing between characters).

† and you probably want them to be, at least in a European language, because it is much easier to read text broken only on whitespace than text broken mid-word, even if it results in the text looking slightly more ragged.

多情出卖 2024-08-04 23:33:51

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

}

GetBoxedString method of the StringBoxer class "estimates" the amount of string (Space-separated words, Enter-separated words or even long characters) you can put in a rectangle and returns it (Be careful when copying/pasting it because I couldn't fit whole my code in the gray box below):

public sealed class 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;
}

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文