使用QPainter的drawPixmap/drawImage绘制图像,图像看起来模糊

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

我使用QPainter的

drawPixmap() 
来绘制图像,结果如下图B所示。

然后,我在Windows提供的图像查看程序中打开同一张图像,将其放大得更小,如下图A所示。

drawPixmap.jpeg 很明显B比A大,但没有A那么清晰。B有明显的Aliasing。

我尝试了

setRenderHint(QPainter::Antialiasing)
setRenderHint(QPainter::SmoothPixmapTransform)
,有一定效果,但不足以解决问题。

我尝试了不同的方法来显示相同的图像(OpenGL、webEngine、QPainter.drawPixmap、graphicsView),结果各不相同,但它们的质量都低于Windows内置图像查看器。

QOpenGLWidget.png

我认为这不是图像清晰度的问题。当我使用drawPixmap()绘制图像并调用QPainter的scale()方法放大它时,我可以看到图像的细节。

有谁知道如何在Qt中绘制与内置Windows软件相同清晰度的图像?即使当我缩小图像时,我也想避免锯齿问题。

-- 编辑 --

最小可重现演示:

// canvaswidget.h
#ifndef CANVASWIDGET_H
#define CANVASWIDGET_H

#include <QWidget>

class CanvasWidget : public QWidget
{
    Q_OBJECT
public:
    explicit CanvasWidget(QImage img, QWidget *parent = nullptr);
    void zoomIn();
    void zoomOut();

signals:

protected:
    QSize sizeHint();
    void paintEvent(QPaintEvent *event) override;
    void wheelEvent(QWheelEvent *event) override;

private:
    qreal scale;
    QPixmap pixmap;
};

#endif // CANVASWIDGET_H
// canvaswidget.cpp
#include "canvaswidget.h"
#include <QWheelEvent>
#include <QPainter>
#include <QPixmap>

CanvasWidget::CanvasWidget(QImage img, QWidget *parent)
    : QWidget{parent}, scale(1.0)
{
    // make sure high resolution source
    pixmap = QPixmap::fromImage(img.scaled(img.size() * 10, Qt::KeepAspectRatio, Qt::SmoothTransformation));
}

void CanvasWidget::zoomIn() {
    scale = fmin(scale + 0.1, 10);
    update();
}

void CanvasWidget::zoomOut() {
    scale = fmax(scale - 0.1, 0.1);
    update();
}

void CanvasWidget::paintEvent(QPaintEvent *event) {
    if(!pixmap) {
        return QWidget::paintEvent(event);
    }
    QPainter p(this);

    p.setRenderHint(QPainter::Antialiasing);
    p.setRenderHint(QPainter::SmoothPixmapTransform);
    p.drawPixmap(0,0,width() * scale,height() * scale, pixmap); // draw image
}

void CanvasWidget::wheelEvent(QWheelEvent *event)
{

    if(event->modifiers() == Qt::ControlModifier) {
        QPointF delta = event->angleDelta();
        int v_delta = delta.y();
        if(v_delta > 0) {
            zoomIn();
        } else {
            zoomOut();
        }
        update();
        adjustSize();
    } else {
        QWidget::wheelEvent(event);
    }
}
QSize CanvasWidget::sizeHint()
{
    return QSize(800,800);
}

下图左边是本次demo的结果,右边是Windows内置的图像查看器。

enter image description here

--- 编辑 2 ---

这是我在演示中使用的图像,它的格式是

QImage::Format_ARGB32
,大小是
QSize(1541, 1188)
25KB PNG enter image description here

qt qpainter qpixmap
1个回答
0
投票

我的问题在某种意义上已经解决了,让我总结一下,希望它可以帮助其他像我一样陷入困境的人

我计划实现一个支持放大和缩小图像的图像查看器。我用来缩小的方法如下:

CanvasWidget::CanvasWidget(QImage img, QWidget *parent)
    : QWidget{parent}, scale(1.0)
{
    pixmap = QPixmap::fromImage(img);
}

void CanvasWidget::paintEvent(QPaintEvent *e) {
    QPainter p(this);
    p.drawPixmap(0,0,width() * scale, height() * scale, pixmap);
    // ...
}

在这种方法中,当我缩小时图像变得模糊。我尝试了几种方法,例如: • 在绘制图像之前缩放 QPainter:

painter.scale(scale, scale);
• 使用
QGraphicsView
显示图像 • 使用
QWebEngineView
显示图像

QGraphicsView
QWebEngineView
中,图像随视图调整大小。但是,当视图调整为较小尺寸时,图像仍然变得模糊。

我什至尝试在

QOpenGLWidget
中将图像绘制为纹理,但当调整为较小尺寸时,图像仍然显得模糊。

最后,我意识到这些方法在调整容器大小时无意中缩小了图像,导致图像变得模糊。


我的实现不能被认为是“错误”,它只是不符合我的要求。

Qt Doc 说:

在某些情况下,将像素图绘制到具有比例集的画家可能比缩放像素图更有利。例如,当画家基于 OpenGL 或比例因子快速变化时,就会出现这种情况。

如果你想在缩小时保持图像质量,你应该按照 Christian 所说的实现以下方法。

p.drawPixmap(0, 0, pixmap.scaled(pixmap.size() * scale, Qt::KeepAspectRatio, Qt::SmoothTransformation));
© www.soinside.com 2019 - 2024. All rights reserved.