警告

本节包含自动从C++翻译到Python的代码片段,可能包含错误。

图像合成示例#

展示了如何使用QPainter中的合成模式。

图像合成示例允许用户使用QPainter支持的任何合成模式组合图像,详细描述在《合成模式》中。

../_images/imagecomposition-example.png

设置资源文件#

图像合成示例需要两个源图像,分别是butterfly.pngchecker.png,它们嵌入在imagecomposition.qrc文件中。该文件包含以下代码

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

有关资源文件的更多信息,请参阅《Qt资源系统》。

ImageComposer类定义#

ImageComposer类是QWidget的子类,实现了三个私有槽,分别为chooseSource("chooseDestination()recalculateResult()

class ImageComposer(QWidget):

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

此外,ImageComposer包含五个私有函数,分别为addOp()chooseImage()loadImage()currentMode()imagePos(),以及私有实例的QToolButtonQComboBoxQLabelQImage

# 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类实现#

我们声明了一个名为resultSize的QSize对象,作为静态常量,宽度和高度均为200。

resultSize = QSize(200, 200)

在构造函数中,我们实例化了一个QToolButton对象,名为sourceButton,并将其iconSize属性设置为resultSize。然后使用addOp()函数实例化了operatorComboBox,并使用该函数填充。此函数接受QPainter::CompositionMode,名为mode,以及一个表示合成模式名称的QString,名为name

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"))

实例化了 destinationButton 并设置了其 iconSize 属性为 resultSize。同时创建了 QLabel 对象 equalLabelresultLabel,并且设置了 resultLabelminimumWidth

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

我们将以下信号连接到相应的槽函数

  • sourceButtonclicked() 信号连接到 chooseSource()

  • operatorComboBoxactivated() 信号连接到 recalculateResult(),以及

  • destinationButtonclicked() 信号连接到 chooseDestination()

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

使用了 QGridLayout 对象 mainLayout 来放置所有的小部件。请注意,将 mainLayoutsizeConstraint 属性设置为 SetFixedSize,这意味着 ImageComposer 的大小不能被调整。

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)

创建了一个 QImage 对象,resultImage,并调用了两次 loadImage() 函数来加载 imagecomposition.qrc 文件中的两个图像文件。然后,我们将 windowTitle 属性设置为“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"))

chooseSource()chooseDestination() 是一些方便的函数,它们使用特定的参数调用 chooseImage()

def chooseSource(self):

    chooseImage(tr("Choose Source Image"), sourceImage, sourceButton)

def chooseDestination(self):

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

chooseImage() 函数根据 titleimagebutton 来加载用户选择的图像。

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

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

recalculateResult() 函数用于计算并显示用户选择的组合模式下的两个图像组合的结果。

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))

addOp() 函数用于向 operatorComboBox 添加一个项目,使用 QComboBoxaddItem 方法。此函数接受一个 QPainter::CompositionMode,mode,以及一个 QString,name。矩形以 Qt::Transparent 填充,然后绘制 sourceImagedestinationImage,最后在 resultLabel 上显示。

def addOp(self, mode, name):

    operatorComboBox.addItem(name, mode)

loadImage() 函数使用 fillRect() 绘制透明背景,并使用 drawImage() 在中央位置绘制 image。然后,将此 image 设置为 button 的图标。

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()

currentMode() 函数返回在 operatorComboBox 中选中的合成模式。

QPainter.CompositionMode ImageComposer.currentMode()

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

我们使用 imagePos() 函数确保 QToolButton 对象,sourceButtondestinationButton,的图像居中。

def imagePos(self, QImage image):

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

`` main()``

函数#

main() 函数创建 QApplicationImageComposer 的实例,并调用其 show() 方法。

if __name__ == "__main__":

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

例子项目 @ code.qt.io