[英]Poor rendering quality in custom QQuickPaintedItem
I have a created a small drawing application in QML, I created a small subclass of QQuickPaintedItem
.我在 QML 中创建了一个小型绘图应用程序,我创建了
QQuickPaintedItem
一个小子类。 Then in QML, I used a MouseArea
to feed the input to my class.然后在 QML 中,我使用
MouseArea
将输入提供给我的班级。 From there I simply store the mouse positions in a vector and then paint the points as I receive onto a QImage
using QPainter
(I used a simple algorithm to draw a quadratic bezier curve using the last three points in my vector).从那里我简单地将鼠标位置存储在一个向量中,然后使用
QPainter
接收到的点绘制到QImage
(我使用一个简单的算法使用向量中的最后三个点绘制二次贝塞尔曲线)。 Then I call QQuickPainted::update()
and in my implementation of QQuickPaintedItem::paint()
I draw the image.然后我调用
QQuickPainted::update()
并在我的QQuickPaintedItem::paint()
实现中绘制图像。 Now the program works ok, but the problem is that the rendering of the painting is quite poor (I am already using QPainter::AntiAliasing
).现在程序运行正常,但问题是绘画的渲染很差(我已经在使用
QPainter::AntiAliasing
)。 Below there is a picture.下面有一张图片。 As you can see the curves are not very sharp and I can see the "pixels" on oblique lines (when I try the same thing with OneNote everything is smooth and nice).
正如您所看到的,曲线不是很锐利,我可以看到斜线上的“像素”(当我用 OneNote 尝试同样的事情时,一切都很顺利和漂亮)。
Here is the a full example from my github repository if you want to test it out (the code is below as well).如果您想对其进行测试,这是我的 github 存储库中的完整示例(代码也在下面)。 Is there something I can do about this?
我能做些什么吗?
.
.
#ifndef DRAWINGCANVAS_H
#define DRAWINGCANVAS_H
#include <QObject>
#include <QQuickPaintedItem>
#include <QPixmap>
#include <QPainter>
struct Outline{
QPolygonF points;
void addPoint(QPointF p){
points.append(p);
}
void clear(){
points.clear();
}
};
// a custom QQuickPainted used as a canvas in QML
class DrawingCanvas : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(bool drawing READ drawing WRITE setDrawing NOTIFY drawingChanged)
Q_PROPERTY(int penWidth READ penWidth WRITE setPenWidth NOTIFY penWidthChanged)
Q_PROPERTY(QString penColor READ penColor WRITE setPenColor NOTIFY penColorChanged)
public:
explicit DrawingCanvas(QQuickItem *parent = nullptr);
bool drawing() const;
Q_INVOKABLE void initiateBuffer();
Q_INVOKABLE void penPressed(QPointF pos);
Q_INVOKABLE void penMoved(QPointF pos);
Q_INVOKABLE void penReleased();
int penWidth() const;
void paint(QPainter *painter) override;
QString penColor() const;
public slots:
void setDrawing(bool drawing);
void setPenWidth(int penWidth);
void setPenColor(QString penColor);
signals:
void drawingChanged(bool drawing);
void penWidthChanged(int penWidth);
void penColorChanged(QString penColor);
private:
void drawOnBuffer(QPointF pos);
bool m_drawing;
QPixmap m_buffer;
int m_penWidth;
QString m_penColor;
QPointF m_lastPoint;
Outline m_currentOutline;
QRect m_updateRect;
QVector<Outline> m_outlines;
bool m_outlineEraser;
};
#endif // DRAWINGCANVAS_H
#include "drawingcanvas.h"
#include <QPainter>
DrawingCanvas::DrawingCanvas(QQuickItem *parent) : QQuickPaintedItem(parent)
{
m_penWidth = 4;
}
bool DrawingCanvas::drawing() const
{
return m_drawing;
}
void DrawingCanvas::penPressed(QPointF pos)
{
setDrawing(true);
m_currentOutline.addPoint(pos);
m_lastPoint = pos;
}
void DrawingCanvas::penMoved(QPointF pos)
{
if(drawing()){
m_currentOutline.addPoint(pos);
// draw the points on the buffer
drawOnBuffer(pos);
}
m_lastPoint = pos;
}
void DrawingCanvas::penReleased()
{
setDrawing(false);
m_outlines.append(m_currentOutline);
m_currentOutline.clear();
m_lastPoint = QPointF();
}
// draws the actual item
void DrawingCanvas::paint(QPainter *painter)
{
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
QPen pen;
pen.setWidth(penWidth());
pen.setColor(penColor());
painter->setPen(pen);
painter->drawPixmap(m_updateRect, m_buffer, m_updateRect);
m_updateRect = QRect();
}
// draws on the image
void DrawingCanvas::drawOnBuffer(QPointF pos)
{
QPainter bufferPainter;
if(bufferPainter.begin(&m_buffer)){
QPen pen;
pen.setWidth(penWidth());
pen.setColor(penColor());
bufferPainter.setPen(pen);
bufferPainter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
int pointsLength = m_currentOutline.points.length();
QPainterPath path;
// this will help smoothing the curves
if(pointsLength > 2){
auto previousPoint = m_currentOutline.points.at(pointsLength - 3);
auto mid1 = (m_lastPoint + previousPoint)/2;
auto mid2 = (pos + m_lastPoint)/2;
path.moveTo(mid1);
path.quadTo(m_lastPoint, mid2);
bufferPainter.drawPath(path);
}
// update the canvas
int rad = (penWidth() / 2) + 2;
auto dirtyRect = path.boundingRect().toRect().normalized()
.adjusted(-rad, -rad, +rad, +rad);
// change the canvas dirty region
if(m_updateRect.isNull()){
m_updateRect = dirtyRect;
}
else{
m_updateRect = m_updateRect.united(dirtyRect);
}
update(dirtyRect);
m_lastPoint = pos;
}
}
QString DrawingCanvas::penColor() const
{
return m_penColor;
}
int DrawingCanvas::penWidth() const
{
return m_penWidth;
}
void DrawingCanvas::setDrawing(bool drawing)
{
if (m_drawing == drawing)
return;
m_drawing = drawing;
emit drawingChanged(m_drawing);
}
void DrawingCanvas::setPenWidth(int penWidth)
{
if (m_penWidth == penWidth)
return;
m_penWidth = penWidth;
emit penWidthChanged(m_penWidth);
}
void DrawingCanvas::setPenColor(QString penColor)
{
if (m_penColor == penColor)
return;
m_penColor = penColor;
emit penColorChanged(m_penColor);
}
// initiates the QImage buffer
void DrawingCanvas::initiateBuffer()
{
qDebug() << this << "Initiating buffer" << width() << height();
m_buffer = QPixmap(width(), height());
}
In QML:在 QML 中:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.12
import QtQuick.Dialogs 1.3
import Drawing 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Flickable {
id: scrollView
anchors.fill: parent
contentHeight: drawingCanvas.height
DrawingCanvas {
id: drawingCanvas
width: parent.width
height: 2000
penColor: "red"
onWidthChanged: drawingCanvas.initiateBuffer()
}
}
MouseArea {
anchors.fill: parent
anchors.rightMargin: 20
onPressed: drawingCanvas.penPressed(
Qt.point(mouseX, mouseY + scrollView.contentY))
onPositionChanged: drawingCanvas.penMoved(
Qt.point(mouseX, mouseY + scrollView.contentY))
onReleased: drawingCanvas.penReleased()
}
}
Your rendering issue doesn't seem to be due to the antialising qt option but more to the smoothing of your strokes.您的渲染问题似乎不是由于抗锯齿 qt 选项造成的,而更多是由于笔触的平滑。 I recommend you to modify your custom bezier smoothing techniques or to use a dedicated lib for that [0] .
我建议您修改您的自定义贝塞尔平滑技术或为此 [0] 使用专用库。
Secondly, you should create a dedicated QPen in your draw methods and "play" with the QPen and QBrush options [1] if you want the "OneNote drawing feeling".其次,如果你想要“OneNote 绘图感觉”,你应该在你的绘图方法中创建一个专用的 QPen 并使用 QPen 和 QBrush 选项[1]“玩”。 The major difference I saw between the two screenshots was the brush scale dynamics (at the beginning and the end of the strokes).
我在两个屏幕截图之间看到的主要区别是画笔缩放动态(在笔画的开头和结尾)。
0: For example, https://github.com/oysteinmyrmo/bezier 0:例如, https : //github.com/oysteinmyrmo/bezier
1: https://doc.qt.io/qt-5/qpen.html 1: https : //doc.qt.io/qt-5/qpen.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.