一.原理
倒影效果在轮播图中用得比较多,当然音乐频谱中也有用到。通常的做法是将原图垂直镜像,然后在原图下面绘制该镜像图
用Qt获取镜像图比较方便,调用QImage的mirrored方法就行,该方法有两个参数,分别可以控制水平或(和)垂直镜像
获取垂直镜像的代码如下所示
QImage img(":/icons/snow.png");
QImage mirriored = img.mirrored(false, true);
如果给按钮等控件绘制倒影,需要先获取按钮的图像,这一点用Qt也很好实现,如下所示
QPixmap pix(ui->pushButton->size());
ui->pushButton->render(&pix);
接着将pix做垂直镜像就行
QImage mirriored2 = pix.toImage().mirrored(false, true);
如果镜像图不做任何处理,最基础的倒影效果如下图所示
上图中的倒影效果比较生硬,就好比说大树在水中的倒影,并不是和岸上的书一毛一样,有种由近及远渐渐模糊的效果,因此需要给上图中的倒影加渐变,这就涉及到了图像融合(composition)
在Qt Creator中搜索composition,可以看到两个demo,有了这两个demo,还要什么自行车
本文用到的融合模式是QPainter::CompositionMode_DestinationIn,关于该模式,Qt assistant中的解释是
The output is the destination, where the alpha is reduced by that of the source.
可以简单的理解为混合后输出的是目标图像,且目标图像的透明度会随着原图像的透明度的减少而减少,举个例子
// 设置倒影渐变.
painter.begin(&mirriored);
QLinearGradient g(0, 0, 0, mirriored.height());
g.setColorAt(0, QColor(0, 0, 0, 255));
g.setColorAt(1.0, QColor(0, 0, 0, 0));
//设置图像合成模式.
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
painter.fillRect(mirriored.rect(),g);
painter.end();
上面代码中将镜像图作为目标图像,将黑色线性渐变作为原图像,融合以后,输出的是目标图像,但此时目标图像从上到下会越来越透明
实际上这的线性渐变可以是任意颜色,只要透明度是渐变的就行,因为在QPainter::CompositionMode_DestinationIn模式下,原图像只会影响目标图像的透明度
二.实现
完整代码如下:
void QHReflection::paintEvent(QPaintEvent *event)
{
// 图片.---------------------------
QImage backgroundImg(width(), height()/2, QImage::Format_ARGB32_Premultiplied);
backgroundImg.fill(Qt::black);
QImage img(":/icons/snow.png");
QImage mirriored = img.mirrored(false, true);
// 绘制原图.
QPainter painter;
painter.begin(&backgroundImg);
painter.drawImage((width()-img.width())/2, 0, img);
painter.end();
// 设置倒影渐变.
painter.begin(&mirriored);
QLinearGradient g(0, 0, 0, mirriored.height());
g.setColorAt(0, QColor(0, 0, 0, 255));
g.setColorAt(1.0, QColor(0, 0, 0, 0));
// 设置图像合成模式.
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
painter.fillRect(mirriored.rect(),g);
painter.end();
// 绘制倒影.
painter.begin(&backgroundImg);
painter.drawImage((width()-img.width())/2, img.height(), mirriored);
painter.end();
// 将背景绘制到窗口中.
painter.begin(this);
painter.drawImage(0, 0, backgroundImg);
painter.end();
// 按钮.----------------------------
QPixmap pix(ui->pushButton->size());
ui->pushButton->render(&pix);
QImage mirriored2 = pix.toImage().mirrored(false, true);
QImage backgroundImg2(width(), height()/2, QImage::Format_ARGB32_Premultiplied);
backgroundImg2.fill(Qt::white);
// 设置倒影渐变.
painter.begin(&mirriored2);
QLinearGradient g2(0, 0, 0, mirriored2.height());
g2.setColorAt(0, QColor(255, 255, 255, 255));
g2.setColorAt(1.0, QColor(255, 255, 255, 0));
//设置图像合成模式.
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
painter.fillRect(mirriored2.rect(),g2);
painter.end();
// 绘制倒影.
painter.begin(&backgroundImg2);
painter.drawImage(ui->pushButton->x(), ui->pushButton->y()+ui->pushButton->height()-height()/2, mirriored2);
painter.end();
// 将背景绘制到窗口中.
painter.begin(this);
painter.drawImage(0, height()/2, backgroundImg2);
painter.end();
}