我使用QPainter的
drawPixmap()
来绘制图像,结果如下图B所示。
然后,我在Windows提供的图像查看程序中打开同一张图像,将其放大得更小,如下图A所示。
很明显B比A大,但没有A那么清晰。B有明显的Aliasing。
我尝试了
setRenderHint(QPainter::Antialiasing)
和setRenderHint(QPainter::SmoothPixmapTransform)
,有一定效果,但不足以解决问题。
我尝试了不同的方法来显示相同的图像(OpenGL、webEngine、QPainter.drawPixmap、graphicsView),结果各不相同,但它们的质量都低于Windows内置图像查看器。
我认为这不是图像清晰度的问题。当我使用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内置的图像查看器。
--- 编辑 2 ---
这是我在演示中使用的图像,它的格式是
QImage::Format_ARGB32
,大小是QSize(1541, 1188)
25KB PNG
我的问题在某种意义上已经解决了,让我总结一下,希望它可以帮助其他像我一样陷入困境的人。
我计划实现一个支持放大和缩小图像的图像查看器。我用来缩小的方法如下:
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));