How to calcuate font size to fit a text inside a given rectangle



  • Dear all,
    I want to display a text fitting all inside the screen of a mobile device.
    So, I'm trying to find out an efficient way to calculate the correct font size in order to display the text all inside the screen size.

    Any suggestions ??

    Thanks,
    Gianluca.



  • Hi Gianluca.
    Did you try with "QFontMetrics":http://qt-project.org/doc/qt-4.8/qfontmetrics.html ?
    From doc:
    "The QFontMetrics class provides font metrics information.
    QFontMetrics functions calculate the size of characters and strings for a given font.
    ..."
    Regards.



  • I played a bit with QFontMetrics... but if the text is a rich text it continue to work??
    I'm bit confused by the documentation of QFontMetrics::boundingRect:

    "Newline characters are processed as normal characters, not as linebreaks."

    So, it seems that it returns the boundingRect as if the text is written on a long single line.

    And it say nothing about right text :-(

    Thanks,
    Gianluca.



  • I'm in the same boat. I'm given a rectangle size, and I want to grow my font to fit within a rectangle. I think QFontMetrics allows you to calculate a rectangle with a string, not a font size based off of a rectangle.


  • Moderators

    if you want to do checks with rich text you will need to do this with QTextDocument instead. You can use the following methods for this:

    QTextDocument::setHtml()
    QTextDocument::setPageSize();
    QTextDocument::setDefaultFont()
    QTextDocument::::documentLayout()->documentSize()



  • But the question is the opposite.
    I want to know what should be the font size in order to fit inside a given rectangle.
    With the documentSize() method only, for get the answer of the above question I should iterate over all possible font size starting from 1 until I get the value corresponding to the nearest documentSize() to the given rectangle.
    But this procedure it's very heavy and the computational cost is not acceptable.


  • Moderators

    exactly... AFAIK there is no function which provides it the other way around.
    What are the estimated bounds of the font size in your case?
    5pt - 30pt ... meaning 25 iterations in worst case. What system you developing for? Embedded?



  • I'm developing for mobile platforms.
    I would like to get a way to estimate the font size to drastically reduce the number of iterations. Because 20 iterations on setting font on a QTextDocument and ask the documentSize() it seems too much for me.
    It's too much because I need to do the calculation during the dynamical changing of the screen dimension due to rotations or to the appear of keyboard. And in that situations if my code spend more than few milliseconds to calculate the new fontsize the animation will be crap.
    Using a QTextDocument, I cannot do more that 5 iterations.

    Also, calculating the bounds for the font size it's not too easy if I don't know the answer to my question. Because, there are many different phones and tablets with so many different screen dimension and density of pixel that It's unreasonable to use a bounds that works for all mobile devices.
    Instead, if I can figure out a way to estimate the font size for a given rectangle, I can use the routine to calculate the bounds of the font on the basis of the maximum dimension for the rectangle depending on the screen resolution of the mobile device.


  • Moderators

    have you tested it ... i mean performance wise?
    I would assume you could easily load 50 iterations at least without noticing (depending on the device ofc).



  • Yes, I tested... only visually not with precise timing.
    And, If the program do more than 5 iterations the rotation animation (from landscape to portrait and viceversa) will stop about in the middle and then restart.
    I suppose that the delay of iterations in the code that block the GUI thread, blocks also the animations.
    (On a very cheap mobile phone).



  • Maybe I am not understanding, but can't you just use the initial rich-text result as a scale?

    If you take your initial estimated font size (f) and your resulting rich-text rect (r) and your size constraint (c) you should be able to get it in one try with a formula like this:

    int meanSize = r.width * r.height;
    int meanCanvas = c.width * c.height;
    int newPixelSize = floor( f * (meanCanvas / meanSize) );

    So for example my test text renders to 200 x 335 inside a 210x210 space at 24px font:
    meanSize = 67000
    meanCanvas = 44100
    newPixelSize = 15.797 => 15

    It works in my tests:

    [code]Mean volume: 50576
    Canvas volume: 29736
    Scale 12 to 7
    Mean volume: 50184
    Canvas volume: 34846
    Scale 12 to 8
    Mean volume: 48928
    Canvas volume: 47978
    Scale 12 to 11
    Mean volume: 51800
    Canvas volume: 71154
    Scale 12 to 16
    Mean volume: 52680
    Canvas volume: 120053
    Scale 12 to 27
    Mean volume: 54000
    Canvas volume: 128028
    Scale 12 to 28 [/code]

    Here's the relevant method. It's a basic QMainWindow object with a QTextBrowser as the central widget called 'textBrowser':

    [code]void MainWindow::resizeEvent(QResizeEvent *e)
    {
    QSizeF meanSize = ui->textBrowser->document()->size();
    int meanVolume = meanSize.width() * meanSize.height();
    qDebug() << "Mean volume:" << meanVolume;
    if( meanVolume <= 0 )
    return;

    int canvasVolume = ui->textBrowser->width() * ui->textBrowser->height();
    qDebug() << "Canvas volume:" << canvasVolume;
    if( canvasVolume <= 0 )
        return;
    
    int pixelSize = ui->textBrowser->fontInfo().pixelSize();
    
    int newPixelSize = qFloor( (double)pixelSize * ( (double)canvasVolume / (double)meanVolume ) );
    qDebug() << "Scale" << pixelSize << "to" << newPixelSize;
    
    QMainWindow::resizeEvent(e);
    

    }[/code]



  • Nice.

    I have the same question for a QSplashScreen...

    Because splash->showMessage( richText ) enables you to set some styled and translated document, is seems impossible to know its original size, and tweak the font as you proposed.

    Any clue ?



  • Here is my code the fit (in heigth) a text, works quite well (error < 2% I guess) :

    void scalePainterFontSizeToFit(QPainter &painter, QFont &r_font, float _heightToFitIn)
    {
        float oldFontSize, newFontSize, oldHeight;
    
        // Init
        oldFontSize=r_font.pointSizeF();
    
        // Loop
        for (int i=0 ; i<3 ; i++)
        {
            oldHeight = painter.fontMetrics().boundingRect('D').height();
            newFontSize = (_heightToFitIn / oldHeight) * oldFontSize;
            r_font.setPointSizeF(newFontSize);
            painter.setFont(r_font);
            oldFontSize = newFontSize;
            //qDebug() << "OldFontSize=" << oldFontSize << "HtoFitIn=" << _heightToFitIn << "  fontHeight=" << oldHeight << "  newFontSize=" << newFontSize;
        }
    
        // End
        r_font.setPointSizeF(newFontSize);
        painter.setFont(r_font);
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.