Image Composition Example▲
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:
&
lt;!
DOCTYPE RCC&
gt;&
lt;RCC version=
"1.0"
&
gt;
&
lt;qresource&
gt;
&
lt;file&
gt;images/
butterfly.png&
lt;/
file&
gt;
&
lt;file&
gt;images/
checker.png&
lt;/
file&
gt;
&
lt;/
qresource&
gt;
&
lt;/
RCC&
gt;
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 : public
QWidget
{
Q_OBJECT
public
:
ImageComposer();
private
slots:
void
chooseSource();
void
chooseDestination();
void
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
:
void
addOp(QPainter::
CompositionMode mode, const
QString &
amp;name);
void
chooseImage(const
QString &
amp;title, QImage *
image, QToolButton *
button);
void
loadImage(const
QString &
amp;fileName, QImage *
image, QToolButton *
button);
QPainter::
CompositionMode currentMode() const
;
QPoint imagePos(const
QImage &
amp;image) const
;
QToolButton *
sourceButton;
QToolButton *
destinationButton;
QComboBox *
operatorComboBox;
QLabel *
equalLabel;
QLabel *
resultLabel;
QImage sourceImage;
QImage destinationImage;
QImage resultImage;
}
;
ImageComposer Class Implementation▲
We declare a QSize object, resultSize, as a static constant with width and height equal to 200.
static
const
QSize resultSize(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 QPainter::CompositionMode, mode, and a QString, name, representing the name of the composition mode.
ImageComposer::
ImageComposer()
{
sourceButton =
new
QToolButton;
sourceButton-&
gt;setIconSize(resultSize);
operatorComboBox =
new
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 QLabels equalLabel and resultLabel are created and resultLabel's minimumWidth is set.
destinationButton =
new
QToolButton;
destinationButton-&
gt;setIconSize(resultSize);
equalLabel =
new
QLabel(tr("="
));
resultLabel =
new
QLabel;
resultLabel-&
gt;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().
connect(sourceButton, &
amp;QAbstractButton::
clicked,
this
, &
amp;ImageComposer::
chooseSource);
connect(operatorComboBox, &
amp;QComboBox::
activated,
this
, &
amp;ImageComposer::
recalculateResult);
connect(destinationButton, &
amp;QAbstractButton::
clicked,
this
, &
amp;ImageComposer::
chooseDestination);
A QGridLayout, mainLayout, is used to place all the widgets. Note that mainLayout's sizeConstraint property is set to QLayout::SetFixedSize, which means that ImageComposer's size cannot be resized at all.
QGridLayout *
mainLayout =
new
QGridLayout;
mainLayout-&
gt;addWidget(sourceButton, 0
, 0
, 3
, 1
);
mainLayout-&
gt;addWidget(operatorComboBox, 1
, 1
);
mainLayout-&
gt;addWidget(destinationButton, 0
, 2
, 3
, 1
);
mainLayout-&
gt;addWidget(equalLabel, 1
, 3
);
mainLayout-&
gt;addWidget(resultLabel, 0
, 4
, 3
, 1
);
mainLayout-&
gt;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"
, &
amp;sourceImage, sourceButton);
loadImage(":/images/checker.png"
, &
amp;destinationImage, destinationButton);
setWindowTitle(tr("Image Composition"
));
}
The chooseSource() and chooseDestination() functions are convenience functions that invoke chooseImage() with specific parameters.
void
ImageComposer::
chooseSource()
{
chooseImage(tr("Choose Source Image"
), &
amp;sourceImage, sourceButton);
}
void
ImageComposer::
chooseDestination()
{
chooseImage(tr("Choose Destination Image"
), &
amp;destinationImage, destinationButton);
}
The chooseImage() function loads an image of the user's choice, depending on the title, image, and button.
void
ImageComposer::
chooseImage(const
QString &
amp;title, QImage *
image,
QToolButton *
button)
{
QString fileName =
QFileDialog::
getOpenFileName(this
, title);
if
(!
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.
void
ImageComposer::
recalculateResult()
{
QPainter::
CompositionMode mode =
currentMode();
QPainter painter(&
amp;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-&
gt;setPixmap(QPixmap::
fromImage(resultImage));
}
The addOp() function adds an item to the operatorComboBox using QComboBox's addItem function. This function accepts a QPainter::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.
void
ImageComposer::
addOp(QPainter::
CompositionMode mode, const
QString &
amp;name)
{
operatorComboBox-&
gt;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.
void
ImageComposer::
loadImage(const
QString &
amp;fileName, QImage *
image,
QToolButton *
button)
{
image-&
gt;load(fileName);
// Scale the image to given size
*
image =
image-&
gt;scaled(resultSize, Qt::
KeepAspectRatio);
QImage fixedImage(resultSize, QImage::
Format_ARGB32_Premultiplied);
QPainter painter(&
amp;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-&
gt;setIcon(QPixmap::
fromImage(fixedImage));
*
image =
fixedImage;
recalculateResult();
}
The currentMode() function returns the composition mode currently selected in operatorComboBox.
QPainter::
CompositionMode ImageComposer::
currentMode() const
{
return
(QPainter::
CompositionMode)
operatorComboBox-&
gt;itemData(operatorComboBox-&
gt;currentIndex()).toInt();
}
We use the imagePos() function to ensure that images loaded onto the QToolButton objects, sourceButton and destinationButton, are centralized.
QPoint ImageComposer::
imagePos(const
QImage &
amp;image) const
{
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.
int
main(int
argc, char
*
argv[])
{
Q_INIT_RESOURCE(imagecomposition);
QApplication app(argc, argv);
ImageComposer composer;
composer.show();
return
app.exec();
}