Fog Creek Software
Discussion Board




Speaking of math....


This is one of those rare situations where my lack of math skills is a hindrance.

One of my clients wanted to build a custom hit counter for their client's auctions on eBay. For each client, they wanted to provide the ability to specify the font and the font size. (Also, the colors but that isn't important here.)

Creating the code that generates an image is no problem for this, but one of things that I have to do is select an size for the image.

Obviously, the image size for the counter is dependent on the font and the font size that are used. Let's say for an 18 point Arial font, the image size is 54X60. What does it need to be for a 19 point font? 36 points?

Well, the first solution is simply divide 54 and 60 by 18, and get the number of pixels per point. Unfortunately, this won't work as the font size gets progressively larger because the image becomes too big. Likewise, as you go down in font size, the image becomes too small.

So, I have enough math to understand that this function isn't linear. That's why my little equation doesn't work for all font sizes.

My trouble is I'm dealing with 3 variables. If I were expressing X in terms of Y, then I can do that. That's simple algebra.

But what I need to know what the values of X and Y will be for a given font-size. Even if I were to determine the image size for several more variations of font size, I still don't know how to create a simple formula to express the image size as a function of the font size.

Obviously, I could figure it the image size manually for all reasonable font sizes, but that's just way too ugly. I know that there is a way to figure this out, but it's beyond me.

So, math wizards, how do I do this?

Loci
Monday, May 10, 2004

SizeF sizef = grfx.MeasureString(strText, font);

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemdrawinggraphicsclassmeasurestringtopic.asp

Just me (Sir to you)
Monday, May 10, 2004

Not a math anything here, but if I were in your shoes, I'd keep a factor to scale my image, for each range of font size values, instead of computing aspect ratios.

Select Case Font.Size
    Case Between 8 and 12
        FactorX = (say) 1.2
        FactorY = 1.2

    Case Between 12 and 18
        FactorX = 1.5
        FactorY = 1.5
End Select

Img.Width = OriginalWidth * FactorX
Img.Height = OriginalHeight * FactorY

Where Originals are either constants or stored in a data structure or in Tag properties.

Sathyaish Chakravarthy
Monday, May 10, 2004

How about taking the cowards way out, and generate an image way too big for the text no matter what size font you use and then trimming the image?

If the first google hit I came across is correct though, points aren't actually related to pixels.  Points are a physical measurement, with 72 points per inch in postscript.

So, to accurately set the resolution in points, you'd need to know the size of their display.  Basically, points are for print.

Or you could just let the client specify the font size in pixels.

Steve Barbour
Monday, May 10, 2004

"SizeF sizef = grfx.MeasureString(strText, font);"

Dohp!

I let my math anxiety focus my attention on the math rather than the basic solution staring me in the face.

Loci
Monday, May 10, 2004

If it's a fixed-width font, the dimensions of the output image are proportional to the size of the input string.  If it's not a fixed-width font, you'll need to sum the width of each character to get the output width, and find the maximum height of all characters to get the output height.

If all you've got about the fonts is sets of splines, finding the bounding box of the splines for an individual character is relatively straightforward, and that bounding box is what's used to calculate character width/height.


Monday, May 10, 2004

"If it's not a fixed-width font, you'll need to sum the width of each character to get the output width."

Actually, that's not always true.  Antialiasing, cleartyping, bolding, italicising and kerning will all affect the length of a string. 

You simply can't do math with rendered string lengths.  They are not guaranteed to scale proportionally, and the length of two combined strings is not guaranteed to be the length of one plus the length of the other.

The only thing you can do is make the API call to calculate the string width.

Alyosha`
Monday, May 10, 2004

Yes that's correct, the per-character bounding box that I was talking about is calculated based on the font.  For fixed-width fonts, that box will be constant (whether the font's strong or italic, etc).  For variable-width fonts, the dimensions of that box will vary.  Yes you also have to take intercharacter spacing into account, but that's a simple constant.

How do you think the OS function does it?  That's it.


Monday, May 10, 2004

"but that's a simple constant"

Saepe sed non semper.

Alyosha`
Monday, May 10, 2004

> Yes you also have to take intercharacter spacing into account, but that's a simple constant.

Rubish.  This is totally not true.  There are so many variables that effect font layout, that it is almost impossible to determine the size of a string with out rendering it first.  Font layout at low resolution (say on the screen), the character spacing is NOT fixed.  There are many times where the character spacing is not a constant number of pixels.  If you round up or down, by the end of the line you will have a significant accumlated error. 

This is one of the most expensive calculations in our charting engine.  There is no theoritical solution to the problem, and you must come up with a heuristic that includes a "close enough" fudge factor.

christopher baus (www.baus.net)
Tuesday, May 11, 2004

*  Recent Topics

*  Fog Creek Home