1

我正在寻找稳定的算法来在二维表面上水平和垂直地绘制可能较长的文本。这不是特定于语言的,因此如果您可以提供任何语言的示例,那将非常有帮助。

我有以下关于我要绘制的文本和表面的信息:

文字信息:

  • 以 px 为单位的文本大小(行高),当然远小于表面的高度
  • 字体(可以是任何字体)
  • 从 ASCII32 到 ASCII126 的简单字符集
  • 文字可能比较长,单词之间用空格隔开
  • 一旦不再适合表面的宽度,文本应该在空格上“自动”中断
  • 文字是英文的。

表面信息:

  • 宽度和高度
  • 全局坐标系中的 x 和 y 坐标(假设原点在屏幕的左上角)

我确实实现了自己的方法,但它非常不稳定:文本散布在表面上,对齐不正确,有时根本不居中。虽然找不到有用的东西,但也搜索了一些好的方法。我希望stackoverflow社区可以帮助我。非常感谢你。

4

3 回答 3

2

该方法在概念上很简单,有点涉及执行。它只涉及几个步骤:

Split the text into lines that will fit horizontally
Compute the vertical position of the first line
for each line
    Compute its width and the X position
    Display it at the Y position
    Add the line height to the current Y position

困难的部分是第一步。其余的很容易。

如果你有一个固定宽度的字体,那么将文本分成几行并不难。您只需计算给定宽度可以容纳多少个字符,将字符串索引到该位置,然后返回到前一个分词。将子字符串从上一行的开头(或第一行的字符串开头)抓取到该位置,这就是您的行。重复直到到达字符串的末尾。

使用可变宽度字体,事情会有些困难,因为您不能只按n * character_width字符索引字符串。相反,您必须猜测、测试、改进猜测等。我使用过的每个图形子系统都有某种MeasureString方法可以告诉我在给定特定字体的情况下渲染字符串需要多少像素。鉴于此,我过去所做的是:

Divide the surface width by the font's average character width
Index that far into the string, and find the next (or previous) word break.
Measure the string
If the result is wider than the width, go back one word and measure again.
If the result is narrower than the width, go forward one word and measure again.
Repeat the measure/adjust until you find the string that will fit.

找到适合的子字符串后,将起始索引向前移动到下一行的开头,然后再做一次,直到到达字符串的末尾。

垂直居中线组:

starting_position.Y = (Surface_height - (num_lines * line_height)) / 2

水平居中一条线很容易实现:

starting_position.X = (Surface_width - Measured_string_width) / 2

您必须计算starting_position.X每一行的。Y 坐标line_height每连续增加一行。

于 2011-10-15T04:35:00.463 回答
1

所以你有几个规则要遵循

  • 将每一行文本居中
  • 如果一行的长度>页面宽度,则开始一个新行
  • 将整个文本垂直居中

因此,您将输入的空间标记化。您将需要一个字符串集合和一个 currentIndex。当lines[currentIndex] + token.length < pageWidth 时,您可以将token 添加到lines[currentIndex]。一旦条件失败,您增加 currentIndex 并继续。

输入完成后,将每行水平居中。您必须以像素为单位计算每条线的宽度。然后你做 x = pageWidth/2 - lineWidth/2。

然后对您的文本块高度进行相同的计算,但考虑所有行(可能使用文本周围的边界矩形)。然后你可以用同样的公式 y = pageHeight/2 - textHeight /2 得到 y 值

于 2011-10-15T04:29:13.107 回答
0

这是个人方法。如果文本长度不超过 30 个字符,并且空格前​​的第一个单词不超过 15 个字符,这将起作用。然而,这个特性可以很容易地改变。文本将保存在二维数组中,如果一行不够大,它将保存在 2 行中。保存以二维数组为中心的文本后,绘制它很简单。我希望这会有所帮助。

char[][] t = new char[2][15];

public void putTextInMatrix(String text) {
    int len = text.length();
    int start;
    if(len<=15) {
        start = (15-len)/2;
        for (int i=0, j=0; i<15; i++)
            if(i<start || i>=len+start)
                t[0][i] = ' ';
            else {
                t[0][i] = text.charAt(j);
                j++;
            }
    }
    else {
        int last = len;
        for (int i=0; i<15; i++) {
            if (text.charAt(i) == ' ')
                last = i;
        }
        start = (15-last)/2;
        for (int i=0, j=0; i<15; i++)
            if(i<start || i>=last+start)
                t[0][i] = ' ';
            else {
                t[0][i] = text.charAt(j);
                j++;
            }

        start = (15-(len-last))/2;
        for (int i=0, j=last+1; i<15; i++)
            if(i<start || j>=len)
                t[1][i] = ' ';
            else {
                t[1][i] = text.charAt(j);
                j++;
            }
    }
}
于 2012-07-05T16:50:13.080 回答