views:

546

answers:

4

String.length will only tell me how many characters are in the String. (In fact, before Ruby 1.9, it will only tell me how many bytes, which is even less useful.)

I'd really like to be able to find out how many 'en' wide a String is. For example:

'foo'.width
# => 3

'moo'.width
# => 3.5          # m's, w's, etc. are wide

'foi'.width
# => 2.5          # i's, j's, etc. are narrow

'foo bar'.width
# => 6.25         # spaces are very narrow

Even better would be if I could get the first n en of a String:

'foo'[0, 2.en]
# => "fo"

'filial'[0, 3.en]
# => "fili"

'foo bar baz'[0, 4.5en]
# => "foo b"

And better still would be if I could strategize the whole thing. Some people think a space should be 0.25en, some think it should be 0.33, etc.

+8  A: 

It depends on the font used. If you use a fixed width font, it'll be equal to length. If you use other fonts, it'll be something else. Any such function would have to depend on the font used for rendering.

Mehrdad Afshari
There's no question it would depend on the font. If I recall correctly, though, Java has a Font object that you can use to do these sorts of determinations. I don't know of a Ruby Font library.
James A. Rosen
+2  A: 

You could attempt to create a standarized "width proportion table" to calculate an aproximation, basically you need to store the width of each character and then traverse the string adding up the widths.

I found this table here:

Left, Width, Advance values for ArialBD16 'c' through 'm'
Letter  Left Width Advance
c        1      7      9
d        1      8      10
e        1      8      9
f        0      6      5
g        0      9      10
h        1      8      10
i        1      2      4
j       -1      4      4
k        1      8      9
l        1      2      4
m        1       12      14

If you want to get serious, I'd start by looking at webkit, gecko, and OO.org, but I guess the algorithms for kerning and size calculation are not trivial.

krusty.ar
+3  A: 

You should use the RMagick gem to render a "Draw" object using the font you want (you can load .ttf files and such)

The code would look something like this:

   the_text = "TheTextYouWantTheWidthOf"
   label = Draw.new
   label.font = "Vera" #you can also specify a file name... check the rmagick docs to be sure
   label.text_antialias(true)
   label.font_style=Magick::NormalStyle
   label.font_weight=Magick::BoldWeight
   label.gravity=Magick::CenterGravity
   label.text(0,0,the_text)
   metrics = label.get_type_metrics(the_text)
   width = metrics.width
   height = metrics.height

You can see it in action in my button maker here: http://risingcode.com/button/everybodywangchungtonite

diclophis
just be sure to set the font size with "label.pointsize = THE_SIZE", otherwise RMagick will default to a font size of 12.
catwood