上一篇文章:Qt桌面白板工具其一(解决曲线不平滑的问题——贝塞尔曲线)
一、前言:
我比较啰嗦,可能会说很多废话。在上一篇文章中,我主要分享了有关贝塞尔算法解决曲线不平滑的问题,简单来说我们可以通过算法,对所搜集的一系列点进行重新绘制,在画布中绘制我们需要的QPaintPath路径。这个过程中,我一直有在考虑荧光笔的实现问题。荧光笔,简单来说就是绘制一条半透明的线段,常见于需要对一些显示文本进行高亮提示。而采用上述贝塞尔整条路径线条绘制的方法,确实能实现。不过一旦放弃整段路径绘制,转而采用线段叠加的方式绘制线条,就难免会出现因为多条不透明线段叠加,所产生的重复点颜色较深的情况,如图:
经过尝试,一旦整段路径,也就是QPaintPath中添加的线段过多,单次绘制的时候会产生比较严重的耗时。这在鼠标拖动moveevent和刷新显示paintevent中,是不能忍受的。如果需要采用贝塞尔算法,我会选择在鼠标move过程中先采用线段叠加法,在鼠标release释放的时候再统一绘制所采集的点集和线段。又或者将线段拆开,但难免会有凸点和重合点。
上面都是题外话了,本篇文章中想要实现的,是在move过程中,即便采用线段叠加,也能实现荧光笔的效果。这个要求,需要我实现线段叠加的时候,不能产生重合区域颜色较深现象。这个问题在过往很长一段时间内困扰了我很久,但现在终于是解决了。
二、混合模式
首先,分享一个概念QPainter.CompositionMode(附带链接),这是QPainter的绘制混合模式。
被绘制的画布叫做“目标”,需要绘制上去的东西叫做“源”。
而一般来说,QPainter默认的是CompositionMode_SourceOver,即覆盖模式。如果底部有一条实色的红线,你绘制一条半透明绿线,将会产生叠加色。
图一
而如果选择CompositionMode_Source,则是重合部分都只显示“源”,而忽略“目标”的部分。
图二
可以看出,虽然绿线是半透明的,但实际上重合部分已经没有了红色。
所以,本文第一张图的绿色重合点,就能完美解决了,即半透明绿色线段的叠加,重合部分只会显示后一条线段的颜色,透明度通道不会产生叠加,进而形成一条完整的半透明统一透明度的线条。
好啦,以上其实只是为了绘制绿色线段而已,不要被这两张图的红线绿线混淆了,实际上我们需要实现的是图一的效果。
三、简单代码分享
以下是我的操作步骤
//画布资源
QImage *draw_image = nullptr; //qimage画布,最终结果
QImage last_image; //记录动作开始前的原图
QImage temp_image; //中间的临时图片
QImage layer_image; //中间图层,单个动作的图层
QVector<QPointF> ployline_points; //移动中搜集的点集
void xxx::mousePressEvent(QMouseEvent *event)
{
last_image = draw_image->copy(); //记录动作开始前的原图
temp_image = last_image; //move过程中临时显示的图片层
layer_image.fill(Qt::transparent); //图层层,填充透明
ployline_points.clear();
ployline_points.append(event->pos(<