4

I need to find the font size of a text that fits in a box.

Given my current font size, I can get the bounding rectangle of the text.

If I set some arbitrary min and max font size, I suppose I can increment or decrement my font size until I get to the given box.

I am thinking bisection method:

ChangeFontMethod(float currentFont, float reqWidth)

    float minFont = 1, maxFont = 1000
    int tolerance = 0.001, maxIter = 1000 
    int n = 1

    float currentWidth = textWithCurrentFont.boundingRect.Width

    do
        if currentWidth = reqWidth
            break
        else if currentWidth < reqWidth
            minFont = currentFont
        else
            maxFont = currentFont

        if maxFont - minFont < tolerance 
            break

        currentFont = (minFont + maxFont)/2
        currentWidth = textWithCurrentFont.boundingRect.Width
        n++

    while n <= maxIter

    return currentFont

From what I read it should have logarithmic speed, but also I read that it is "slow"

Is there a better way ?

I don't know if I can improve my search by assuming a relationship between font size and font width - definitely there is one, but it's non-linear. So I don't know how to even improve the speed by a better "first guess"

  • The relationship between font "size" and font width may not actually be linear, but it will be approximately linear. – John R. Strohm Jul 1 '15 at 15:22
  • @JohnR.Strohm I have tried to just multiply my current font with the reqWidth/curentWidth ratio... the results are way off the scale. The font changes a lot slower. It doesn't help that, based on the text contents, some letters are taking less space than others, so the relationship between font size and text width is affected not only by the amount of text, but also by the actual letters used, as well as font type. That's why I have to approximate.. iterate... guess... – Thalia Jul 1 '15 at 15:23
  • 1
    So if the current box is too large currentWidth > reqWidth then you search in the larger interval with [currentFont, maxFont]? And if it is too small you search in the smaller interval [minFont, currentFont]? Isn't that backwards? – dpmcmlxxvi Jul 1 '15 at 15:53
  • @dpmcmlxxvi Fixing, thanks - that's what I meant but my subroutine for translating thoughts to pseudocode is buggy – Thalia Jul 1 '15 at 17:25
  • 1
    Bisection requires that you have the final solution bracketed, but otherwise assumes nothing about the form of the solution. If you know something about the form of the solution, you also have a way of estimating where to look for the solution. Use that to guess your new font, rather than just bisecting, and iterate, and you have what numerical analysis people call the "false position method". (Note: Hamming's "modified false position method" is better. Newton's method is far better, but you don't have the derivative available.) – John R. Strohm Jul 1 '15 at 18:54
3

I am not going to code it but I will give you a math approach. Assuming you know the resulting width with two different font sizes:
font size 1 (s1) implies text width 1 (w1) (the small value)
font size 2 (s2) implies text width 2 (w2) (the bigger value)
then your linear estimate of size (s3) that will fit the required width (w) is from using manipulating this formula:
(s3-s1)/(s2-s1)=(w-w1)/(w2-w1)
so estimate correct width is
s3 = s1+(w-w1)*(s2-s1)/(w2-w1)

now you check w3 (the width when using s3). If w < w3 then repeat the method but using s1,w1,s3,w3 if w > w3 then repeat the method but using s3,w3,s2,w2.
This iterative approach only requires that the width for a given text is a monotonic function of the font size, in other words doesn't matter if linear but it will converge faster if the function is closer to linear, so it will accelerate convergence as the range of font sizes reduces.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.