Как использовать маску с QPainter?

У меня есть форма (в синем), загруженная из PNG с прозрачностью:

enter image description here

Затем я рисую несколько кругов поверх этой фигуры (красным цветом) с QPainter::drawEllipse.

enter image description here

Результат этого несколько похож на третье изображение с красной формой, полностью покрывающей синий цвет:

enter image description here

Однако я хотел бы, чтобы синяя фигура выступала в качестве маски к красной, с результатом вроде этого:

enter image description here

Можно ли сделать это с помощью QPainter?

Ответ 1

Это возможно. Предполагая, что вы загружаете PNG в QImage, вы можете сделать что-то вроде этого, чтобы создать маску из вашего изображения:

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

См. другие функции create*Mask в QImage для альтернатив.

Тогда это простой вопрос настройки области клипа художника:

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

Здесь глупая демонстрация (не используйте этот код как есть, загрузка изображения, маска и создание региона должны быть кэшированы, они потенциально дороги):

#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);
        }
};

Что-то вроде этого: enter image description here