2

I'm trying to draw text on a widget at an angle which is non-perpendicular, i.e. between 0 and 90. Drawing the text itself is no issue, but the resulting text is very wiggly/unevenly drawn.

In the picture below, I'm drawing to lines of text at a 45 degree angle. The first line of text is many underscores ("_____"), and second line of text is "Multithreading". Underscores are drawn here instead of a line just to highlight the issue.

enter image description here

As you can see, the first line obviously shows the text is not evenly drawn. This is more subtle in the second line, but still visible.

Drawing at perpendicular angles (0, 90, 180, etc.) does not cause this effect. Any reason why this is happening?

I'm working on Windows 10 with Qt 5.7.0.

Minimal code example:

void MyWidget::paintEvent( QPaintEvent * /* event */ )
{
    QFont font;
    font.setPointSize( 16 );
    font.setStyleStrategy( QFont::StyleStrategy::PreferAntialias );
    setFont( font );

    QImage image( size(), QImage::Format_ARGB32_Premultiplied );
    QPainter imagePainter( &image );
    imagePainter.initFrom( this );
    imagePainter.setFont( font() );
    imagePainter.setRenderHint( QPainter::Antialiasing, true );
    imagePainter.eraseRect( rect() );
    // Set logical origo in the middle of the image
    m_window = QRect(
        - width() / 2,  // x
        - height() / 2, // y
        width(),        // w
        height()        // h
    );
    imagePainter.setWindow( m_window );
    m_viewport = QRect(
        0,              // x
        0,              // y
        width(),        // w
        height()        // h
    );
    imagePainter.setViewport( m_viewport );

    draw( imagePainter );
    imagePainter.end();

    QPainter widgetPainter( this );
    widgetPainter.drawImage( 0, 0, image );
}

void MyWidget::draw( QPainter & painter )
{
    painter.save();
    // Rotate anti-clockwise
    painter.rotate( -m_degrees );
    painter.drawText( m_window.top(), 0, tr( "Multithreads" ) );
    painter.drawText( m_window.top(), 15, tr( "__________" ) );

    painter.restore();
}
edvardsp
  • 133
  • 8
  • Can you try using Antialiasing? – king_nak Sep 25 '17 at 11:08
  • Do you draw character at a time, or strings? – Yakk - Adam Nevraumont Sep 25 '17 at 11:16
  • Antialiasing is enabled, and I'm drawing whole strings. – edvardsp Sep 25 '17 at 11:20
  • Is the QPainter drawing to a QWidget? If so, try drawing to a QImage with antialiasing enabled first and then draw the resulting QImage to the QWidget (the antialiasing hint doesn't always work when drawing directly to a QWidget). – G.M. Sep 25 '17 at 11:26
  • @G.M., this is currently how I'm doing this; drawing to a QImage first, then drawing the QImage to the widget. – edvardsp Sep 25 '17 at 11:31
  • Could you provide some minimal code that you use for drawing the text? – AMA Sep 25 '17 at 11:42
  • @AMA, see edited post. – edvardsp Sep 25 '17 at 11:49
  • What's happening in `draw( imagePainter );`? – AMA Sep 25 '17 at 11:52
  • And how do you create `QImage` without specifying `Format`? – AMA Sep 25 '17 at 11:55
  • Did you try using `HighQualityAntialiasing`? I remember I had a similar problem inside `QGraphicsScene`. But even if it works I doubt it will solve your problems. After all a widget is not drawn as vector graphics hence jaggies and wiggly lines are to be expected. – rbaleksandar Sep 25 '17 at 11:55
  • `draw( imagePainter )` calls the second method listed beneath the `paintEvent()` method. `QImage` is specified with an format, I accidentally removed it when making the code example. – edvardsp Sep 25 '17 at 11:57
  • @rbaleksandar, I've tried with all the different aliasing options. The result is still the same. – edvardsp Sep 25 '17 at 11:57
  • What is the font that you are using? On linux the situation is much better, even though the underscores are not perfectly aligned. Unfortunately, can't attach an image to a comment. – AMA Sep 25 '17 at 11:58
  • @AMA, I'm using the default font, Arial in this case. I've tried with other font families as well, with varying degrees of unaligned text. – edvardsp Sep 25 '17 at 11:59
  • Last guess: is your `MyWidget` a `QGLWidget`? OpenGL does not support as nice text-antialiasing (if at all) compared to the software rendering. – AMA Sep 25 '17 at 12:02
  • @Ama, MyWidget inherits QWidget, so no. – edvardsp Sep 25 '17 at 12:05
  • Your drawing is definitely antialiased, as in how individual characters are drawn. It seems that the issue is with aliasing or rounding of the character positions when they are at an angle that is not `!(angle % 90)`. Maybe you should file a bug report. – dtech Sep 25 '17 at 12:59

1 Answers1

5

I found a workaround from this Qt bug ticket. In short, the fix is to draw the text as a QPainterPath rather than as text.

Example of the fix is

// Do this
QPainterPath glyphPath;
glyphPath.addText( x, y, painter.font(), text );
painter.fillPath( glyphPath, painter.pen().color() );
// instead of this
painter.drawText( x, y, text );

EDIT:

The difference can be seen below.

Before:

Before, buggy text

After:

After, correct text

edvardsp
  • 133
  • 8
  • Could you please add an image with the result? I'm curious how much of an improvement this work-around provides. – AMA Sep 25 '17 at 15:50