views:

1091

answers:

7

This is a long shot, but does anyone know of an algorithm for estimating and categorising text width (for a variable width font) based on its contents?

For example, I'd like to know that iiiiiiii is not as wide as abcdefgh, which in turn is not as wide as WWWWWWWW, even though all three strings are eight characters in length.

This is actually an attempt to build some smarts into a string truncation method, which at the moment is correctly truncating a visually wide string, but is also unnecessarily truncating a visually narrow string, because both strings contain the same number of characters. It's probably sufficient for the algorithm to categorise the input string as narrow, normal or wide and then truncate as appropriate.

This question isn't really language-specific, but if there is an algorithm then I'll implement it in Java. This is for a web application. I'm aware that there are answers on SO that deal with this problem using JavaScript to obtain the width of a containing div element, but I wondered if a server-side solution is possible.

+12  A: 

Most GUI frameworks provide some way to calculate text metrics for fonts on given output devices.

Using java.awt.FontMetrics, for example, I believe you can do this:

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

Not tested, but you get the idea.


Under .Net you can use the Graphics.MeasureString method. In 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));
}
Mark Pim
Maaaybe, but in this case you have the issue of what Graphics context you pick on your server...
Neil Coffey
I've accepted this answer because it actually attempted to address my question as asked, even though the question was kind of ridiculous and clearly not something you'd attempt for real!
John Topley
Graphics2D g=new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB).createGraphics();
larson4
+1  A: 

I think you should choose one of these solutions:

  • Exact solution: Sum up the width for every character in the string (most APIs will give you this information)
  • Quick estimate: Either take the maximum or the minimum width and multiply it with the numbers of characters.

Of course some mixed estimate is possible, but I think this is too much effort in the wrong direction.

schnaader
+1  A: 

This is actually an attempt to build some smarts into a string truncation method [...]

Is it really worth the effort? We had this exact problem. And this was across languages. The fix was to leave it as-is. The complexity of keeping this intelligence up increases rapidly (and probably exponentially) with every language that you add support for. Hence our decision.

[...] an algorithm for estimating and categorising text width (for a variable width font) based on its contents?

Most font-libraries will give you this information. But this is pretty low-level stuff. The basic idea is to pass in a string and get back the width in points.

dirkgently
No, it's not really worth the effort for the problem I have to solve, but it has piqued my intellectual curiosity!
John Topley
Hm. FWIW, I have updated my answer with my personal experience.
dirkgently
+1  A: 

For a nice* client-side solution, you could try a hybrid CSS-and-Javascript approach as suggested by RichieHindle's answer to my question.

Given that you don't know what font the user will see the page in (they can always override your selection, Ctrl-+ the page, etc), the "right" place to do this is on the browser... although browsers don't make it easy!

* when I say "nice", I mean "probably nice but I haven't actually tried it yet".

Sam Stokes
i belive the language here is Java...
Peter Perháč
+2  A: 

For a web application, you cannot (really) get a proper estimation. Different fonts have different widths, so that this not only depends on the client (browser) and its zoom and DPI settings, but also on the fonts present on that machine (and operating system) or their substitutions.

If you need exact measuring, create a graphic (bitmap, SVG, or even some PDF or whatever) which will be layouted and rendered on the server and not on the client.

Lucero
+2  A: 

There is no reliable server side solution for calculating width of text. (outside of creating an image of the text and probably SVG)

If you try a tool out like browser-shots and run it against relatively basic pages, you'll immediately see why. It's hard to predict how wide even the most mundane examples will turn out, much less if a user decides to zoom in the browser etc...

It's not stated precisely you might want to truncate the string (it might be helpful in giving potential solutions), but a common one is because you want to cut off the text at some point and provide an ellipse.

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

altCognito
+2  A: 

You really have no way of knowing what browser, font settings, screen size etc the client is using. (OK, sometimes the request headers provide an indication, but really nothing consistent or reliable.)

So, I would:

  • display some sample text in Internet Explorer with default settings on a screen/window size of 1024x768 (this is generally the most common size)
  • take an average characters/line with this configuration and use that for your estimate.

I've generally found this "good enough", for example, for estimating the number of lines that some text will take up on a browser, in order to estimate how many adverts to show next to the text.

If it was really really crucial to you, then I can imagine a convoluted scheme whereby you initially send some Javascript to the client, which then takes a measurement and sends it back to your server, and you then use this information for future pages for that client. I can't imagine it's usually worth the effort, though.

Neil Coffey
Instead of having client-side Javascript report back the text width, wouldn't it be easier to pop up a messagebox asking the user to magnify the text 8x in Paint, print it out and mail it to a given address? :-P
j_random_hacker
If you do that, I would actually suggest serializing the graphics context at the time of printing and then sending that to the server, thus saving on vital e-mail traffic-- don't want to overload the UK's big brother database with unnecessary e-mails!
Neil Coffey
Definitely! :)
j_random_hacker