单像素宽度笔会忽略 MiterJoin

问题描述 投票:0回答:1

问题

在启用抗锯齿功能的 QPainter 上绘制线宽为 1px 的矩形时,无论设置什么 JoinStyle,都会导致角稍微透明。对于折线和 QPainterPaths 也可以观察到同样的情况

def paintEvent(self, event):
    with QPainter(self) as p:
        p.setRenderHint(QPainter.Antialiasing, True)

        p.fillRect(self.rect(), QColor('black'))
        p.setBrush(Qt.NoBrush)

        # 1px width border, corner is partially transparent
        p.setPen(QPen(QColor("orange"), 1, cap=Qt.SquareCap, join=Qt.MiterJoin))
        p.drawRect(QRectF(10.5, 10.5, 50., 25.))

        # 3px width border, corner is crisp
        p.setPen(QPen(QColor("orange"), 3, cap=Qt.SquareCap, join=Qt.MiterJoin))
        p.drawRect(QRectF(15.5, 15.5, 50., 25.))

产生以下输出:

both corners use Qt.MiterJoin, but the 1px corner is not as crisp

问题

有没有办法让 1px 宽的笔获得清晰的角,同时也适用于部分透明的线条和任意 QPainterPaths?

到目前为止尝试过的解决方案

  • 单独绘制每条线:
    工作正常,但由于拐角处重叠,存在部分透明线条的伪像。

  • 单独绘制每条线,但将每条线的开头移动 1:
    解决了部分透明直线直角的问题,但不能解决其他角度或曲线的问题。

  • 暂时禁用抗锯齿:
    对角线和曲线变得锯齿状。

qt pyqt5 qt5
1个回答
0
投票

这是由私有 QCosmeticStroker 引起的,QPainter 在绘制画笔宽度在 0 到 1(含)之间的路径(在绘画设备比例中)时使用该私有 QCosmeticStroker。

在抗锯齿模式下绘制“像素完美”线条一直有点复杂,并且总是存在一定程度的妥协(以及可能的错误)。

同样,该描边器虽然通常准确、快速且高效,但在某些情况下可能会失败(要了解实际情况有多么复杂,请参阅其当前的实现),而人们会认为绘制一个简单的方角可能不会这可能是一个问题,在处理“多段线”(也可能包括曲线)和闭合路径的模块化绘制时可能会出现这个问题。

还要考虑到,对于 1 像素宽的笔,连接样式差异几乎可以忽略不计:默认的斜角连接将填充 87.5% 的像素区域,而圆形连接则约为 94.6%。

不过,它可能仍然值得报告错误。

在任何情况下,一个简单的解决方法是防止笔触发挥作用:只需使用略大于 1 的笔宽度。这可能会有点效率低下,因为画家需要检查是否即使对于直正交线,线也会超出“像素边界”,因此几乎没有必要尝试应用抗锯齿,但如果图像精度更重要,那么这是可以接受的成本:

# no need to set the cap, which already defaults to square
p.setPen(QPen(QColor("orange"), 1.0001))
© www.soinside.com 2019 - 2024. All rights reserved.