基于内容的文本宽度估算算法

时间:2009-04-29 16:09:43

标签: java algorithm text

这是一个很长的镜头,但有没有人知道根据其内容估算和分类文本宽度(对于可变宽度字体)的算法?

例如,我想知道 iiiiiiii 并不像 abcdefgh 那么宽,而 abcdefgh 又不如 WWWWWWWW 那么宽>,即使所有三个字符串的长度都是八个字符。

这实际上是尝试将一些智能构建到字符串截断方法中,该方法目前正在截断视觉上宽的字符串,但也不必要地截断视觉上狭窄的字符串,因为两个字符串包含相同数量的字符。算法可能足以将输入字符串分类为 narrow normal wide ,然后根据需要进行截断。

这个问题并不是特定于语言的,但如果有算法,那么我将用Java实现它。这适用于Web应用程序。我知道SO上有答案可以解决这个问题,使用JavaScript来获取包含div元素的宽度,但我想知道服务器端解决方案是否可行。

8 个答案:

答案 0 :(得分:15)

大多数GUI框架提供了一些计算给定输出设备上字体的文本度量的方法。

例如,使用java.awt.FontMetrics,我相信你可以这样做:

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics; 

public int measureText(Graphics g, String text) {
   g.setFont(new Font("TimesRoman", Font.PLAIN, 12));
   FontMetrics metrics = g.getFontMetrics();

   return metrics.stringWidth(text);
}

未经测试,但您明白了。


在.Net下,您可以使用Graphics.MeasureString方法。在C#中:

private void MeasureStringMin(PaintEventArgs e)
{

    // Set up string.
    string measureString = "Measure String";
    Font stringFont = new Font("Arial", 16);

    // Measure string.
    SizeF stringSize = new SizeF();
    stringSize = e.Graphics.MeasureString(measureString, stringFont);

    // Draw rectangle representing size of string.
    e.Graphics.DrawRectangle(new Pen(Color.Red, 1), 0.0F, 0.0F, stringSize.Width, stringSize.Height);

    // Draw string to screen.
    e.Graphics.DrawString(measureString, stringFont, Brushes.Black, new PointF(0, 0));
}

答案 1 :(得分:5)

这对我有用:

AffineTransform af = new AffineTransform();     
FontRenderContext fr = new FontRenderContext(af,true,true);     
Font f = new Font("Arial", 0, 10); // use exact font
double width= f.getStringBounds("my string", fr).getWidth();      

答案 2 :(得分:2)

对于Web应用程序,您无法(真正)获得正确的估算。不同的字体具有不同的宽度,因此这不仅取决于客户端(浏览器)及其缩放和DPI设置,还取决于该计算机(和操作系统)上存在的字体或其替换。

如果您需要精确测量,请创建一个图形(位图,SVG,甚至某些PDF或其他),这些图形将在服务器上而不是在客户端上进行布局和渲染。

答案 3 :(得分:2)

没有可靠的服务器端解决方案来计算文本宽度。(在创建文本图像和SVG之外)

如果你尝试使用像browser-shots这样的工具并在相对基本的页面上运行它,你会立即明白原因。很难预测即使最平凡的例子会变得多么广泛,更不用说如果用户决定放大浏览器等......

没有准确地说明你可能想要截断字符串(它可能有助于提供潜在的解决方案),但常见的是因为你想在某个点切断文本并提供一个椭圆。

This can be done reliably on many browser platforms by using a css property, and NO javascript:

http://www.jide.fr/emulate-text-overflowellipsis-in-firefox-with-css

答案 4 :(得分:2)

您真的无法知道客户端使用的浏览器,字体设置,屏幕大小等。 (好的,有时请求标头提供了指示,但实际上没有任何一致性或可靠性。)

所以,我会:

  • 在Internet Explorer中显示一些示例文本,默认设置为1024x768的屏幕/窗口大小(这通常是最常见的大小)
  • 使用此配置获取平均字符/行,并将其用于估算。

我通常发现这个“足够好”,例如,用于估算某些文本在浏览器上占用的行数,以便估计文本旁边显示的广告数量。

如果它对您真的非常重要,那么我可以想象一个复杂的方案,您最初向客户端发送一些Javascript,然后进行测量并将其发送回您的服务器,然后您将此信息用于将来该客户的页面。但我无法想象它通常值得付出努力。

答案 5 :(得分:1)

我认为您应该选择以下解决方案之一:

  • 精确解决方案:总结字符串中每个字符的宽度(大多数API会为您提供此信息)
  • 快速估算:取最大或最小宽度,然后乘以字符数。

当然可能会有一些混合估计,但我认为这是在错误的方向上付出太多努力。

答案 6 :(得分:1)

  

这实际上是尝试将一些智能构建成字符串截断方法[...]

真的值得努力吗?我们遇到了这个问题。这是跨语言的。修复是保持原样。保持这种智能的复杂性随着您添加支持的每种语言而迅速(并且可能呈指数级)增加。因此我们的决定。

  

[...]根据内容估算和分类文本宽度(可变宽度字体)的算法?

大多数字体库都会为您提供此信息。但这是相当低级的东西。基本思想是传入一个字符串并以磅为单位返回宽度。

答案 7 :(得分:1)

对于一个不错的*客户端解决方案,您可以尝试RichieHindle's answer to my question建议的混合CSS和Javascript方法。

鉴于您不知道用户将看到该页面的字体(它们总是可以覆盖您的选择,Ctrl- +页面等),在浏览器上执行此操作的“正确”位置。虽然浏览器不容易!

*当我说“好”时,我的意思是“可能很好但我还没有尝试过”。