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

11
这是一个冒险,但有没有人知道基于内容估算和分类文本宽度(对于变宽字体)的算法?
例如,我想知道iiiiiiii不如abcdefgh宽,后者又不如WWWWWWWW,尽管这三个字符串的长度都为八个字符。
实际上,这是一种将智能添加到字符串截断方法的尝试。目前,这种方法正确地截断了一个视觉宽度的字符串,但也不必要地截断了一个视觉狭窄的字符串,因为两个字符串包含相同数量的字符。该算法可能足以将输入字符串分类为狭窄正常,然后根据需要进行截断。
这个问题并不特定于语言,但如果有算法,我会在Java中实现它。这是一个Web应用程序。我知道有一些SO答案使用JavaScript获取包含
元素的宽度来处理此问题,但我想知道是否有服务器端解决方案。
8个回答

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

2
也许吧,但在这种情况下,您需要考虑在服务器上选择哪个图形上下文的问题... - Neil Coffey
我接受了这个答案,因为它实际上试图回答我提出的问题,尽管这个问题有点荒谬,明显不是你会尝试去做的事情! - John Topley
Graphics2D g = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB).createGraphics(); 在此代码中,创建了一个宽高为100像素,图像类型为INT_ARGB的缓冲图像,并获取其Graphics2D对象。 - jwl

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

我在谷歌上搜索了两天才找到这样的东西,谢谢! - Natalia

2

对于一个Web应用程序,你不能(真正)得到一个适当的估计。不同的字体有不同的宽度,因此这不仅取决于客户端(浏览器)及其缩放和DPI设置,还取决于安装在该机器上(和操作系统)的字体或其替代品。

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


2

目前没有可靠的服务器端解决方案来计算文本宽度。(除非创建文本图像或SVG)

如果你尝试使用类似browser-shots这样的工具运行相对简单的页面,你会立即看到为什么。很难预测即使是最平凡的例子会有多宽,更不用说用户决定在浏览器中放大等情况了...

虽然没有明确说明你可能想截断字符串(这可能有助于提供潜在的解决方案),但常见的一种方法是在某个点上截断文本并提供省略号。

可以通过使用CSS属性而不需要JavaScript来在许多浏览器平台上可靠地完成此操作:

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


2
您真的无法知道客户端使用的浏览器、字体设置、屏幕尺寸等。 (好吧,有时请求头提供了一些指示,但真的没有什么一致或可靠的东西。)
所以,我会:
- 在Internet Explorer上显示一些默认设置的样本文本,并在1024x768的屏幕/窗口大小下显示。(这通常是最常见的大小) - 采用此配置的平均字符/行数,并将其用于您的估算。
我通常发现这已经"足够好了",例如,为了估计某些文本在浏览器上占据多少行,以便估计在文本旁边显示多少广告。
如果对您来说真的非常重要,那么我可以想象一个复杂的方案,即您最初向客户端发送一些Javascript,然后它会进行测量并将其发送回到您的服务器,然后您可以将此信息用于该客户端的未来页面。不过,我想通常情况下这并不值得努力。

不如弹出一个消息框,要求用户在Paint中将文本放大8倍,然后打印并邮寄到指定地址,这样比让客户端Javascript报告文本宽度更容易,哈哈。:-P - j_random_hacker
1
如果您这样做,我实际上建议在打印时序列化图形上下文,然后将其发送到服务器,从而节省重要的电子邮件流量--不想用不必要的电子邮件超载英国的大兄弟数据库! - Neil Coffey

1

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

  • 精确解决方案:对字符串中每个字符的宽度进行求和(大多数 API 都会提供这些信息)
  • 快速估算:取最大或最小宽度并将其乘以字符数。

当然,有些混合估计也可能可行,但我认为这是在错误的方向上花费太多的精力。


1
这实际上是尝试在字符串截断方法中加入一些智能的尝试。值得这么做吗?我们曾经遇到过完全相同的问题,而且跨越了多种语言。解决方法是保持原样。随着每种语言的增加,保持这种智能的复杂度会迅速增加(可能呈指数级增长)。因此,我们做出了这个决定。
对于基于内容估算和分类文本宽度(针对可变宽度字体)的算法,大多数字体库都会提供这些信息。但这是非常底层的东西。基本思想是传入一个字符串并返回点数宽度。

不,对于我要解决的问题来说,这并不值得花费那么多精力,但它引起了我的求知欲! - John Topley
嗯。顺便说一下,我已经用我的个人经验更新了我的答案。 - dirkgently

1

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

考虑到您不知道用户将在哪种字体中查看页面(他们总是可以覆盖您的选择,Ctrl-+页面等),因此进行此操作的“正确”位置是在浏览器上...尽管浏览器并不容易!

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接