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(); }
-
@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 ofQPainter::translate
andQPainter::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.
-
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:
- 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. - 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.
- Letters are not squares (we're talking TTF fonts here) so when you