How to use a mask with QPainter?

laurent picture laurent · Sep 24, 2011 · Viewed 15.5k times · Source

I have a shape (in blue) loaded from a PNG with transparency:

enter image description here

Then I'm drawing several circles on top of this shape (in red) with QPainter::drawEllipse.

enter image description here

The result of that is somewhat similar to the third picture with the red shape completely covering the blue one:

enter image description here

What I would like however is for the blue shape to act as a mask to the red one, with a result like this:

enter image description here

Is it possible to do that with QPainter?

Answer

Mat picture Mat · Sep 24, 2011

It's possible. Assuming you're loading your PNG into a QImage, you can do something like this to create a mask from your image:

QImage img("your.png");
QPixmap mask = QPixmap::fromImage(img.createAlphaMask());

See the other to create*Mask functions in QImage for alternatives.

Then it's a simple matter of setting the painter's clip region:

QPainter p(this);
p.setClipRegion(QRegion(mask));

Here's a stupid demo (don't use that code as-is, the image loading, mask and region creation should be cached, they are potentially expensive):

#include <QtGui>

class W: public QWidget
{
    Q_OBJECT
    public:
        W(): QWidget(0) { }

    protected:
        void paintEvent(QPaintEvent *)
        {
            QPainter p(this);
            QImage img("../back.png");
            QPixmap mask = QPixmap::fromImage(img.createAlphaMask());

            // draw the original image on the right
            p.drawImage(300, 0, img);

            // draw some ellipses in the middle
            p.setBrush(Qt::red);
            for (int i=0; i<100; i+=10)
                p.drawEllipse(i+150, i, 20, 70);

            // and do the same thing, but with the mask active
            p.setClipRegion(QRegion(mask));
            for (int i=0; i<100; i+=10)
                p.drawEllipse(i, i, 20, 70);
        }
};

Which produces something like this: enter image description here