使用 Qt 绘制像素完美的圆
Posted
技术标签:
【中文标题】使用 Qt 绘制像素完美的圆【英文标题】:Drawing pixel-perfect circles with Qt 【发布时间】:2019-02-20 00:00:52 【问题描述】:我正在尝试使用QPainter::drawEllipse
来绘制圆圈。我希望能够:
QPen::width
)
选择圆心像素的形状(1x1
、1x2
、2x1
或 2x2
)
可选择填充圆而不是描边
确保圆的半径正确(即使笔划宽度大于 1)
这些目标难以实现。这是我要渲染的示例(手工绘制):
图片为 32x32(放大至 512x512)。红色中心点位于 (15, 15)。中心是1x2
,所以在中心像素下方有一个额外的红色像素。笔划的宽度为 2 个像素。如果笔画变宽,像素将被添加到圆圈的内部。无论笔画宽度如何,圆的边界框都是相同的。半径为 8 像素。每条蓝线长 8 个像素。 为了清楚起见,红色和蓝色像素只是用于描述圆圈。它们不是我想要的输出的一部分。
我的问题真正归结为渲染一个完全适合矩形内的椭圆。我可以使用中心点、半径和中心形状来计算矩形。那部分很容易。简单地用这个矩形调用drawEllipse
是行不通的。我想我必须在调用drawEllipse
之前以某种方式调整这个矩形,但我不太确定如何调整它。我试过摆弄它,我找到了一些适用于某些笔宽但不适用于其他笔宽的解决方案。
笔帽重要吗?我一直在使用RoundCap
。我应该使用不同的上限吗?
我几乎要考虑自己进行像素操作了。我正在渲染到QImage
并使用Source
复合操作,因此我的代码可能比drawEllipse
稍快。 memset
比 QImage::fill
快大约 10 倍,因此编写更快的代码可能不会太难!不过,我宁愿不必这样做。
【问题讨论】:
您能否向我们展示一些您尝试过但不完全符合要求的代码?这可能会给你一些更好的答案。 【参考方案1】:我偶然发现了一个section in the docs,它谈到了QRect
s 是如何呈现的。它描述了渲染像素和逻辑矩形之间的关系。渲染的矩形大于逻辑矩形。我所要做的就是缩小逻辑矩形以进行补偿。
QRect adjustStrokedRect(const QRect rect, const int thickness)
return QRect
rect.left() + thickness / 2,
rect.top() + thickness / 2,
rect.width() - thickness,
rect.height() - thickness
;
好的,现在我可以在正确的位置渲染描边矩形。 QRect
描述了一个椭圆,那么如果我只是将这个变换应用于那个矩形呢?
没有。
如果厚度是1, 2, 4, 6
而不是3, 5, 7
,它会起作用。当厚度为3, 5, 7
时,圆圈太小了一个像素。因此,如果thickness % 2 == 1 && thickness != 1
,我尝试将1
添加到矩形大小,但随后从正方形呈现非对称圆形。对于某些位置和大小的组合,即使大小为正方形,也会呈现出不稳定的不对称圆形。
这是一个您可以轻松复制的奇怪图像:
使用以下代码生成它:
QImage image32, 32, QImage::Format_ARGB32_Premultiplied;
QPainter painterℑ
QPen penQt::NoBrush, 3.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin;
pen.setColor(QColor0, 255, 0, 255);
painter.setPen(pen);
painter.drawEllipse(8, 8, 17, 17);
image.save("weird.png");
我简直不明白这怎么可能。对我来说,drawEllipse
似乎正在渲染一个大致适合矩形的椭圆。我无法在文档中的任何地方找到矩形和椭圆之间的关系。也许这是因为这是一种非常松散的关系。
让QPainter::drawEllipse
绘制笔画宽度为1
的圆圈没有问题,所以现在我不允许在我的应用程序中使用粗圆圈。如果我不能完美地渲染它,我根本不会渲染它。我没有将此答案标记为已接受,因为我仍然希望它能够正常工作。
【讨论】:
【参考方案2】:我可能为时已晚,但仍以供将来参考:
不幸的是,Qt 使用贝塞尔曲线绘制椭圆(截至目前,它可能很快就会改变),这是一个很好的椭圆近似,但并不完美。绘制像素完美的椭圆需要在像素级别手动实现。
【讨论】:
以上是关于使用 Qt 绘制像素完美的圆的主要内容,如果未能解决你的问题,请参考以下文章