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.
First, we'll focus on the built-in browser method. Right click on the page you like the look of and select Inspect Element (Firefox), Inspect (Chrome), or F12 Developer Tools (Edge). Select Inspector (Firefox) or Computed (Chrome) in the new bottom windows and scroll down on the right until you reach Font or font-size.
The measureText() method returns an object that contains the width of the specified text, in pixels.
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));
}
This worked for me:
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();
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With