Search code examples
c++qtqpainterqt6drawtext

Qt6 : Applying fonts without any anti-aliasing - any strategy not respected


I'm trying to render text with a QPainter and I do not want anti-aliasing applied. I am fairly new to QT, so might be doing something wrong here. No matter what i've tried there is always some sort of antialiasing. I'll share my code below, which contains some commented lines on various different things that haven't worked

class TextExample : public QMainWindow {
protected:
    void paintEvent(QPaintEvent* aEvent) override {
        QPainter painter(this);

        painter.setRenderHint(QPainter::Antialiasing, false);
        painter.setRenderHint(QPainter::TextAntialiasing, false);
        painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
        painter.setBrush(Qt::black);

        QFont myFont{"Times New Roman", 12};
        myFont.setStyleStrategy(QFont::NoAntialias);
        painter.setFont(myFont);

        // painter.drawStaticText(QPoint{0,0}, QStaticText{"Hello, world!"});

        painter.drawText(10, 50, "Hello, world!");

        // QTextDocument td;
        // td.setHtml("Hello, world!");
        // td.drawContents(&painter);
    }
};

int main(int aArgc, char *aArgv[]) {
    QApplication myApplication{aArgc, aArgv};

    // QFont myFont{"Informal Roman", 12};
    // myFont.setStyleStrategy(QFont::NoAntialias);
    // myFont.setStyleStrategy(QFont::NoSubpixelAntialias);
    // QApplication::setFont(myFont);

    for (const auto myStr : QFontDatabase::families()) {
        qDebug() << myStr;
    }

    TextExample myMainWindow;
    myMainWindow.setWindowTitle("Text Example");
    myMainWindow.resize(800, 600);
    myMainWindow.show();

    return myApplication.exec();
}

I am running this in qt 6.4.0 if that matters on windows 10

Something to note it does actually work with QPainterPath , but i'd prefer to avoid that since its more expensive and also seems to have other issues drawing text.

Another thing to note, is some fonts have no antialiasing so far as I can see, a good example is 'MS Sans Serif'. But produces for me a nice not-so-friendly warning, and similarly QT isn't respecting by strategies in enabling me to add antialiasing for these,

DirectWrite: CreateFontFaceFromHDC() failed (Indicates an error in an input file such as a font file.) for QFontDef(Family="MS Sans Serif", pointsize=12, pixelsize=16, styleHint=5, weight=400, stretch=100, hintingPreference=0) LOGFONT("MS Sans Serif", lfWidth=0, lfHeight=-16) dpi=144

Any help would be infinitely appreciated


Solution

  • Finally was able to determine the issue. The font strategies were being respected, but in Qt6 we have high DPI scaling unlike QT5 , of course you can disable that by setting the environment variable QT_ENABLE_HIGHDPI_SCALING to 0 (which also fixes it for me). However if you want to keep the DPI scaling, this is the solution I was able to find to work.

    The reason it didn't work before is because the text is scaled to this higher resolution DPI and the scaling has the antialiasing automatically applied.

    We need to tell Qt6 to try to choose its font sizing based on the target windows resolution. I was using a High DPI monitor, which is why I was never able to initially even see my posted solution works on a regular scaled monitor.

    Just a warning, from reading the documentation this might not work on OSX, but feel free to add below if it did for the sake of others! This solutions works for Windows:

    class TextExample : public QMainWindow {
        void paintEvent(QPaintEvent*) final {
            QFont myFont{"Times New Roman", 16};
            myFont.setStyleStrategy(QFont::NoAntialias);
    
            // THIS is the key line:
            myFont.setHintingPreference(QFont::HintingPreference::PreferFullHinting);
    
            QPainter myPainter{this};
            myPainter.setFont(myFont);
            myPainter.drawText(10, 50, "Hello, world!");
        }
    };
    
    int main(int aArgc, char *aArgv[]) {
        QApplication myApplication{aArgc, aArgv};
    
        TextExample myMainWindow;
        myMainWindow.setWindowTitle("Text Example");
        myMainWindow.resize(800, 600);
        myMainWindow.show();
    
        return myApplication.exec();
    }
    

    I really hope this helps someone someday, since this caused me a world of pain.