Unexpected interaction between scale and font size



  • I'm seeing some strange artifacts when rendering text with a scaled QPainter. To demonstrate, I put together the following code. It renders very differently on Windows and OS X. And neither are what I expected. I had expected to see the same text at the same size on every line. Am I doing something wrong in the code?

    I don't know how to attach an image to a post. I shared them in my Dropbox public folder:
    Screen capture OS X
    Screen capture Windows

    #include <QtWidgets/QApplication>
    #include <QtWidgets/QWidget>
    #include <QtGui/QPainter>
    
    class MainWindow : public QWidget
    {
    private:
      virtual void paintEvent( QPaintEvent* ) Q_DECL_OVERRIDE
      {
        for( qreal scale = 1; scale <= 20; scale += 1 )
        {
          QPainter painter( this );
          painter.translate( 0, 10 + scale * 25 );
          painter.scale( scale, scale );
          QFont font;
          font.setPointSizeF( 20.0 / scale );
          painter.setFont( font );
          painter.drawText( QPointF( 0, 0 ), QStringLiteral( "Hello, World!" ) );
        }
      }
    };
    
    int main( int argc, char *argv[] )
    {
      QApplication a( argc, argv );
      MainWindow w;
      w.resize( 200, 600 );
      w.show();
      return a.exec();
    }
    

  • Qt Champions 2017

    @rpieket
    The only thing I could think of is the noncommutativity of the transformations and/or some render/representation difference of the fonts between the two systems. Does the snippet work as expected on both systems if you drop the translation? What happens if you switch the order of QPainter::translate and QPainter::scale (which I think would be the proper one)?



  • @kshegunov I added the translation for the purpose of demonstration. It does not affect the seemingly random text size on either platform or strange kerning on Windows.

    Note that the scale and point size change monotonically with every iteration of the loop, but the rendered text size is anything but.


  • Qt Champions 2017

    @rpieket

    virtual void paintEvent( QPaintEvent* ) Q_DECL_OVERRIDE
    {
    	QPainter painter( this );
    	const QString text( "Hello, World!" );
    
    	QFont font;
    	QFontMetrics metrics(font, this);
    	QRect rect = metrics.boundingRect(text);
    	qreal width = rect.width(), height = rect.height();
    
    	qint32 i = 0;
    	for(qreal scale = 1; scale <= 2; scale += .1, i++ )  {
    		painter.save();
    
    		font.setPointSizeF(20.0 / scale );
    		painter.setFont(font);
    
    		QFontMetrics metrics(font, this);
    		QRect rect = metrics.boundingRect(text);
    
    		painter.translate( 0, height * (i + 1) );
    		painter.scale( width / rect.width(), height / rect.height());
    
    		painter.drawText( QPointF( 0, 0 ), text);
    		painter.restore();
    	}
    }
    

    This renders fine on my machine. So the problems are:

    1. Letters are not squares (we're talking TTF fonts here) so when you scale the painter's coordinate system, you're not taking this into account.
    2. The problem with the letters' offsets is because precision is inevitably lost when you take a 1pt sized font and forcefully stretch the coordinate system to make it a 20pt sized font, at least I believe that's the reason.

Log in to reply
 

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