Warning

This section contains snippets that were automatically translated from C++ to Python and may contain errors.

Image Composition Example#

Shows how composition modes work in QPainter .

The Image Composition example lets the user combine images together using any composition mode supported by QPainter , described in detail in Composition Modes .

../_images/imagecomposition-example.png

Setting Up The Resource File#

The Image Composition example requires two source images, butterfly.png and checker.png that are embedded within imagecomposition.qrc. The file contains the following code:

<Code snippet "/data/qt5-full-650/6.5.0/Src/qtbase/painting/imagecomposition/imagecomposition.qrc" not found>

For more information on resource files, see The Qt Resource System .

ImageComposer Class Definition#

The ImageComposer class is a subclass of QWidget that implements three private slots, chooseSource(), chooseDestination(), and recalculateResult().

class ImageComposer(QWidget):

    Q_OBJECT
# public
    ImageComposer()
# private slots
    def chooseSource():
    def chooseDestination():
    def recalculateResult():

In addition, ImageComposer consists of five private functions, addOp(), chooseImage(), loadImage(), currentMode(), and imagePos(), as well as private instances of QToolButton , QComboBox , QLabel , and QImage .

# private
    def addOp(mode, name):
    def chooseImage(title, image, button):
    def loadImage(fileName, image, button):
    QPainter.CompositionMode currentMode()
    imagePos = QPoint(QImage image)
    sourceButton = QToolButton()
    destinationButton = QToolButton()
    operatorComboBox = QComboBox()
    equalLabel = QLabel()
    resultLabel = QLabel()
    sourceImage = QImage()
    destinationImage = QImage()
    resultImage = QImage()

ImageComposer Class Implementation#

We declare a QSize object, resultSize, as a static constant with width and height equal to 200.

resultSize = QSize(200, 200)

Within the constructor, we instantiate a QToolButton object, sourceButton and set its iconSize property to resultSize. The operatorComboBox is instantiated and then populated using the addOp() function. This function accepts a CompositionMode , mode, and a QString , name, representing the name of the composition mode.

def __init__(self):

    sourceButton = QToolButton()
    sourceButton.setIconSize(resultSize)
    operatorComboBox = QComboBox()
    addOp(QPainter.CompositionMode_SourceOver, tr("SourceOver"))
    addOp(QPainter.CompositionMode_DestinationOver, tr("DestinationOver"))
    addOp(QPainter.CompositionMode_Clear, tr("Clear"))
    addOp(QPainter.CompositionMode_Source, tr("Source"))
    addOp(QPainter.CompositionMode_Destination, tr("Destination"))
    addOp(QPainter.CompositionMode_SourceIn, tr("SourceIn"))
    addOp(QPainter.CompositionMode_DestinationIn, tr("DestinationIn"))
    addOp(QPainter.CompositionMode_SourceOut, tr("SourceOut"))
    addOp(QPainter.CompositionMode_DestinationOut, tr("DestinationOut"))
    addOp(QPainter.CompositionMode_SourceAtop, tr("SourceAtop"))
    addOp(QPainter.CompositionMode_DestinationAtop, tr("DestinationAtop"))
    addOp(QPainter.CompositionMode_Xor, tr("Xor"))
    addOp(QPainter.CompositionMode_Plus, tr("Plus"))
    addOp(QPainter.CompositionMode_Multiply, tr("Multiply"))
    addOp(QPainter.CompositionMode_Screen, tr("Screen"))
    addOp(QPainter.CompositionMode_Overlay, tr("Overlay"))
    addOp(QPainter.CompositionMode_Darken, tr("Darken"))
    addOp(QPainter.CompositionMode_Lighten, tr("Lighten"))
    addOp(QPainter.CompositionMode_ColorDodge, tr("ColorDodge"))
    addOp(QPainter.CompositionMode_ColorBurn, tr("ColorBurn"))
    addOp(QPainter.CompositionMode_HardLight, tr("HardLight"))
    addOp(QPainter.CompositionMode_SoftLight, tr("SoftLight"))
    addOp(QPainter.CompositionMode_Difference, tr("Difference"))
    addOp(QPainter.CompositionMode_Exclusion, tr("Exclusion"))

The destinationButton is instantiated and its iconSize property is set to resultSize as well. The QLabel s equalLabel and resultLabel are created and resultLabel's minimumWidth is set.

destinationButton = QToolButton()
destinationButton.setIconSize(resultSize)
equalLabel = QLabel(tr("="))
resultLabel = QLabel()
resultLabel.setMinimumWidth(resultSize.width())

We connect the following signals to their corresponding slots:

  • sourceButton's clicked() signal is connected to chooseSource(),

  • operatorComboBox's activated() signal is connected to recalculateResult(), and

  • destinationButton's clicked() signal is connected to chooseDestination().

sourceButton.clicked.connect(
        self.chooseSource)
operatorComboBox.activated.connect(
        self.recalculateResult)
destinationButton.clicked.connect(
        self.chooseDestination)

A QGridLayout , mainLayout, is used to place all the widgets. Note that mainLayout's sizeConstraint property is set to SetFixedSize , which means that ImageComposer's size cannot be resized at all.

mainLayout = QGridLayout()
mainLayout.addWidget(sourceButton, 0, 0, 3, 1)
mainLayout.addWidget(operatorComboBox, 1, 1)
mainLayout.addWidget(destinationButton, 0, 2, 3, 1)
mainLayout.addWidget(equalLabel, 1, 3)
mainLayout.addWidget(resultLabel, 0, 4, 3, 1)
mainLayout.setSizeConstraint(QLayout.SetFixedSize)
setLayout(mainLayout)

We create a QImage , resultImage, and we invoke loadImage() twice to load both the image files in our imagecomposition.qrc file. Then, we set the windowTitle property to “Image Composition”.

resultImage = QImage(resultSize, QImage.Format_ARGB32_Premultiplied)
loadImage(":/images/butterfly.png", sourceImage, sourceButton)
loadImage(":/images/checker.png", destinationImage, destinationButton)
setWindowTitle(tr("Image Composition"))

The chooseSource() and chooseDestination() functions are convenience functions that invoke chooseImage() with specific parameters.

def chooseSource(self):

    chooseImage(tr("Choose Source Image"), sourceImage, sourceButton)
def chooseDestination(self):

    chooseImage(tr("Choose Destination Image"), destinationImage, destinationButton)

The chooseImage() function loads an image of the user’s choice, depending on the title, image, and button.

def chooseImage(self, title, image,):
                                QToolButton button)

    fileName = QFileDialog.getOpenFileName(self, title)
    if not fileName.isEmpty():
        loadImage(fileName, image, button)

The recalculateResult() function is used to calculate amd display the result of combining the two images together with the user’s choice of composition mode.

def recalculateResult(self):

    QPainter.CompositionMode mode = currentMode()
    painter = QPainter(resultImage)
    painter.setCompositionMode(QPainter.CompositionMode_Source)
    painter.fillRect(resultImage.rect(), Qt.transparent)
    painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
    painter.drawImage(0, 0, destinationImage)
    painter.setCompositionMode(mode)
    painter.drawImage(0, 0, sourceImage)
    painter.setCompositionMode(QPainter.CompositionMode_DestinationOver)
    painter.fillRect(resultImage.rect(), Qt.white)
    painter.end()
    resultLabel.setPixmap(QPixmap.fromImage(resultImage))

The addOp() function adds an item to the operatorComboBox using QComboBox ‘s addItem function. This function accepts a CompositionMode , mode, and a QString , name. The rectangle is filled with Qt::Transparent and both the sourceImage and destinationImage are painted, before displaying it on resultLabel.

def addOp(self, mode, name):

    operatorComboBox.addItem(name, mode)

The loadImage() function paints a transparent background using fillRect() and draws image in a centralized position using drawImage() . This image is then set as the button's icon.

def loadImage(self, fileName, image,):
                              QToolButton button)

    image.load(fileName)
    # Scale the image to given size
    image = image.scaled(resultSize, Qt.KeepAspectRatio)
    fixedImage = QImage(resultSize, QImage.Format_ARGB32_Premultiplied)
    painter = QPainter(fixedImage)
    painter.setCompositionMode(QPainter.CompositionMode_Source)
    painter.fillRect(fixedImage.rect(), Qt.transparent)
    painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
    painter.drawImage(imagePos(image), image)
    painter.end()
    button.setIcon(QPixmap.fromImage(fixedImage))
    image = fixedImage
    recalculateResult()

The currentMode() function returns the composition mode currently selected in operatorComboBox.

QPainter.CompositionMode ImageComposer.currentMode()

    return (QPainter.CompositionMode)
           operatorComboBox.itemData(operatorComboBox.currentIndex()).toInt()

We use the imagePos() function to ensure that images loaded onto the QToolButton objects, sourceButton and destinationButton, are centralized.

def imagePos(self, QImage image):

    return QPoint((resultSize.width() - image.width()) / 2,
                  (resultSize.height() - image.height()) / 2)

The `` main()``

Function#

The main() function instantiates QApplication and ImageComposer and invokes its show() function.

if __name__ == "__main__":

    Q_INIT_RESOURCE(imagecomposition)
    app = QApplication([])
    composer = ImageComposer()
    composer.show()
    sys.exit(app.exec())

Example project @ code.qt.io