imagecomposition工程存放在Qt安装目录下的
Examples\Qt-x.xx.xx\widgets\painting\imagecomposition
目录下。其中
x.xx.xx为Qt的版本号。该工程展示了QPainter::CompositionMode的含义。要弄懂本工程请先参考《QPainter类的CompositionMode各值含义》
,否则本工程对初学者很难弄懂。
预备知识:
把将要画上去的颜色称为“源颜色”,把原来的颜色称为“目标颜色”。初次画的时候,窗体上什么都没有,则窗体或窗体的一个区域(当运用裁剪时)为目标,即将要画上去的图形为源。
弄懂本工程的关键是要搞懂QPainter类的CompositionMode各值含义、源图像和目标图像的概念。
loadImage函数分析
该工程的loadImage函数代码如下:
void ImageComposer::loadImage(const QString &fileName, QImage *image,
QToolButton *button)
{
image->load(fileName);
// Scale the image to given size
*image = image->scaled(resultSize, Qt::KeepAspectRatio);
QImage fixedImage(resultSize, QImage::Format_ARGB32_Premultiplied);
QPainter painter(&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();
}
当代码执行到第11行但11行后的代码没执行时,即将第12、13、19行代码注释掉,根据前面源和目标的定义可以知道:此时窗体为目标,fixedImage为源,根据《QPainter类的CompositionMode各值含义》文章对QPainter::CompositionMode_Source的描述,可以知道,此时只显示源,但因为fixedImage设置为透明的,所以即使显示的是源,但看到的是源后面的窗体,如下:
如果将第11行改为:
painter.fillRect(fixedImage.rect(), Qt::red);
则输出如下:
因为源是红色的,不再透明,所以看不到后面的窗体,显示的是源的红色。将第11行依然设置为红色,取消12、13行注释,则此时11行绘制上去的红色QImage对象fixedImage为目标,第13行绘制的image对象为源,因为绘图组合模式是QPainter::CompositionMode_SourceOver,根据《QPainter类的CompositionMode各值含义》文章对QPainter::CompositionMode_SourceOver的描述,可以知道此时目标和源重叠的部分进行混合,且源盖住(遮挡住)目标,没有重叠部分各自保留即都绘制出来,结果如下:
将第11行依然设置为Qt::transparent,则如下:
在ImageComposer类的构造函数中,通过本函数分别加载了两张图形,一张用于最左侧QToolButton按钮贴图,一张用于中间QToolButton按钮贴图。
recalculateResult函数分析
函数代码如下:
void ImageComposer::recalculateResult()
{
QPainter::CompositionMode mode = currentMode();
QPainter painter(&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));
}
代码执行到第7行时,即代码如下:
void ImageComposer::recalculateResult()
{
QPainter::CompositionMode mode = currentMode();
QPainter painter(&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));
}
目标是QLabel类型的resultLabel子窗体部件,源是透明的QImage类对象resultImage,采用CompositionMode_Source模式绘制,结果就是将resultImage贴在resultLabel子窗体部件上面,因为resultImage是透明的,所以至第7行时,resultImage绘制和没绘制都一样,你看到的都是resultLabel子窗体部件。代码执行到第8、9行时,即代码如下:
void ImageComposer::recalculateResult()
{
QPainter::CompositionMode mode = currentMode();
QPainter painter(&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));
}
设置QPainter::CompositionMode_SourceOver模式后再以resultImage为画布(绘图设备)绘制了destinationImage,此时destinationImage为源,resultImage为目标。根据《QPainter类的CompositionMode各值含义》文章对QPainter::CompositionMode_SourceOver的描述,可以知道此时目标和源重叠的部分进行混合,且源盖住(遮挡住)目标,没有重叠部分各自保留即都绘制出来,结果如下红色方框所示:
代码执行到第10、11行时,即代码如下:
void ImageComposer::recalculateResult()
{
QPainter::CompositionMode mode = currentMode();
QPainter painter(&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));
}
根据界面的选择来设置相应的组合模式,并绘制sourceImage,此时第10行之前绘制的结果即destinationImage为目标,即将要绘制的sourceImage为源,如下红色方框为在界面下拉框选择组合模式为SourceOver的输出:
代码执行到13行,即代码如下时:
void ImageComposer::recalculateResult()
{
QPainter::CompositionMode mode = currentMode();
QPainter painter(&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));
}
此时resultImage为源,之前绘制的为目标,又因为第12行设置模式为QPainter::CompositionMode_DestinationOver,即源图像如果和目标图像有重叠,绘制时,则重叠部分是目标图像在源图像上面(目标遮挡住源),当目标的alpha为255时,源被目标完全遮挡。重叠部分的源和重叠部分的目标进行混合,混合之后得出的RGBA值为重叠部分的RGBA值,没有重叠部分各自保留即都绘制出来。所以最终的输出结果如下:
可以结合《QPainter类的CompositionMode各值含义》文章对各个组合模式的描述,读者自行选择界面下拉框上的不同的模式进行体会、理解。