Why does QPainter.fillRect with transparency leave artifacts?
Solved
QML and Qt Quick
-
main.cpp:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QBuffer> #include <QImage> #include <QPainter> #include <QQmlContext> class ImageSource : public QObject { Q_OBJECT public: ImageSource(QObject* parent=nullptr) : QObject(parent) { } Q_INVOKABLE QString genImageString(QString text){ QImage textimage(64,64, QImage::Format_RGBA8888); // create image QPainter painter(&textimage); //painter.setPen(QColor(255,0,0,255)); //painter.fillRect(0,0,64,64, QColor(0,0,0,255)); painter.fillRect(0,0,64,64, QColor(0,0,0,0)); //painter.fillRect(0,0,64,64, QBrush(Qt::transparent, Qt::BrushStyle::SolidPattern)); painter.setPen(Qt::blue); painter.setFont(QFont("Arial", 20)); painter.drawText(QRect(0,0,64,64), Qt::AlignCenter, text); QByteArray bArray; QBuffer buffer(&bArray); buffer.open(QIODevice::WriteOnly); textimage.save(&buffer, "PNG"); QString image("data:image/png;base64,"); image.append(QString::fromLatin1(bArray.toBase64().data())); return image; } }; int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; ImageSource is; auto context = engine.rootContext(); context->setContextObject(&is); const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); } #include "main.moc"
main.qml:
import QtQuick 2.12 import QtQuick.Window 2.12 Window { visible: true width: 640 height: 480 title: qsTr("QML Image from Source String") GridView { id: gridview anchors.fill: imagetester model: 9 cellWidth: imagetester.width/3 cellHeight: imagetester.height/3 delegate: Rectangle { width: gridview.cellWidth height: gridview.cellHeight color: !(index % 2) ? "lightgrey" : "grey" opacity: 0.75 } } Image { id: imagetester width: 64 height: 64 source: genImageString("Hello") } }
I tried doing a fill with black with alpha set to 255. Then a fill with transparency and it just shows black. Is this an issue with conversion to PNG or the QImage itself?
-
Woah woah woah!!! This is crazy! If I change the image size then it goes away!
main.cpp:#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QBuffer> #include <QImage> #include <QPainter> #include <QQmlContext> class ImageSource : public QObject { Q_OBJECT public: ImageSource(QObject* parent=nullptr) : QObject(parent) { } Q_INVOKABLE QString genImageString(QString text, int width, int height){ QImage textimage(width,height, QImage::Format_RGBA8888); // create image QPainter painter(&textimage); //painter.setPen(QColor(255,0,0,255)); //painter.fillRect(0,0,width,height, QColor(0,0,0,255)); painter.fillRect(0,0,width,height, QColor(0,0,0,0)); //painter.fillRect(0,0,width,height, QBrush(Qt::transparent, Qt::BrushStyle::SolidPattern)); painter.setPen(Qt::blue); painter.setFont(QFont("Arial", 20)); painter.drawText(QRect(0,0,width,height), Qt::AlignCenter, text); QByteArray bArray; QBuffer buffer(&bArray); buffer.open(QIODevice::WriteOnly); textimage.save(&buffer, "PNG"); QString image("data:image/png;base64,"); image.append(QString::fromLatin1(bArray.toBase64().data())); return image; } }; int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; ImageSource is; auto context = engine.rootContext(); context->setContextObject(&is); const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); } #include "main.moc"
main.qml:
import QtQuick 2.12 import QtQuick.Window 2.12 Window { visible: true width: iw height: ih title: qsTr("QML Image from Source String") property int iw: 256 property int ih: iw GridView { id: gridview anchors.fill: imagetester model: 9 cellWidth: imagetester.width/3 cellHeight: imagetester.height/3 delegate: Rectangle { width: gridview.cellWidth height: gridview.cellHeight color: !(index % 2) ? "lightgrey" : "grey" opacity: 0.75 } } Image { id: imagetester width: iw height: ih source: genImageString("Hello", width, height) } }
64x64:
128x128:
-
-
Interesting, the png file that gets written has the same artifacts. So that limits the issue to the painting/image conversion code:
Q_INVOKABLE QString genImageString(QString text, int width, int height){ QImage textimage(width,height, QImage::Format_RGBA8888); // create image QPainter painter(&textimage); //painter.setPen(QColor(255,0,0,255)); //painter.fillRect(0,0,width,height, QColor(0,0,0,255)); painter.fillRect(0,0,width,height, QColor(0,0,0,0)); //painter.fillRect(0,0,width,height, QBrush(Qt::transparent, Qt::BrushStyle::SolidPattern)); painter.setPen(Qt::blue); painter.setFont(QFont("Arial", 20)); painter.drawText(QRect(0,0,width,height), Qt::AlignCenter, text); QByteArray bArray; QBuffer buffer(&bArray); buffer.open(QIODevice::WriteOnly); textimage.save(&buffer, "PNG"); QFile pngfile(QString("image%1%2.png").number(width).number(height)); if(pngfile.open(QIODevice::WriteOnly)){ textimage.save(&pngfile, "PNG"); } pngfile.close(); QString image("data:image/png;base64,"); image.append(QString::fromLatin1(bArray.toBase64().data())); return image; }
-
Okay, found something related:
https://bugreports.qt.io/browse/QTBUG-16264?focusedCommentId=201740&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-201740I most likely need to spend some time learning about the different modes.
Q_INVOKABLE QString genImageString(QString text, int width, int height){ QImage textimage(width,height, QImage::Format_RGBA8888); // create image QPainter painter(&textimage); //painter.setPen(QColor(255,0,0,255)); //painter.fillRect(0,0,width,height, QColor(0,0,0,255)); painter.setCompositionMode(QPainter::CompositionMode_Clear); painter.fillRect(0,0,width,height, QColor(0,0,0,0)); //painter.fillRect(0,0,width,height, QBrush(Qt::transparent, Qt::BrushStyle::SolidPattern)); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); painter.setPen(Qt::blue); painter.setFont(QFont("Arial", 20)); painter.drawText(QRect(0,0,width,height), Qt::AlignCenter, text); QByteArray bArray; QBuffer buffer(&bArray); buffer.open(QIODevice::WriteOnly); textimage.save(&buffer, "PNG"); QFile pngfile(QString("image%1%2.png").number(width).number(height)); if(pngfile.open(QIODevice::WriteOnly)){ textimage.save(&pngfile, "PNG"); } pngfile.close(); QString image("data:image/png;base64,"); image.append(QString::fromLatin1(bArray.toBase64().data())); return image; }