带有像素图图像的 QLabel 变得模糊

QLabel with pixmap image getting blurred

我有一张图片需要显示为 QLabel 的背景。这是我的代码(摘自 Qt 文档 here):

#include <QtWidgets>    
#include "imageviewer.h"

ImageViewer::ImageViewer()
{
    imageLabel = new QLabel;
    imageLabel->setBackgroundRole(QPalette::Base);
    imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    imageLabel->setScaledContents(true);
    setCentralWidget(imageLabel);

    createActions();
    createMenus();

    resize(570,357);
}


bool ImageViewer::loadFile(const QString &fileName)
{
    QImageReader reader(fileName);
    const QImage image = reader.read();
    if (image.isNull()) {
        QMessageBox::information(this, QGuiApplication::applicationDisplayName(),
                                 tr("Cannot load %1.").arg(QDir::toNativeSeparators(fileName)));
        setWindowFilePath(QString());
        imageLabel->setPixmap(QPixmap());
        imageLabel->adjustSize();
        return false;
    }
    imageLabel->setPixmap(QPixmap::fromImage(image).scaled(size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
    return true;
}



void ImageViewer::open()
{
    QStringList mimeTypeFilters;
    foreach (const QByteArray &mimeTypeName, QImageReader::supportedMimeTypes())
        mimeTypeFilters.append(mimeTypeName);
    mimeTypeFilters.sort();
    const QStringList picturesLocations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
    QFileDialog dialog(this, tr("Open File"),
                       picturesLocations.isEmpty() ? QDir::currentPath() : picturesLocations.last());
    dialog.setAcceptMode(QFileDialog::AcceptOpen);
    dialog.setMimeTypeFilters(mimeTypeFilters);
    dialog.selectMimeTypeFilter("image/jpeg");

    while (dialog.exec() == QDialog::Accepted && !loadFile(dialog.selectedFiles().first())) {}
}

void ImageViewer::createActions()
{
    openAct = new QAction(tr("&Open..."), this);
    openAct->setShortcut(tr("Ctrl+O"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));

}

void ImageViewer::createMenus()
{
    fileMenu = new QMenu(tr("&File"), this);
    fileMenu->addAction(openAct);

    menuBar()->addMenu(fileMenu);

}

头文件:

#ifndef IMAGEVIEWER_H
#define IMAGEVIEWER_H

#include <QMainWindow>

class QAction;
class QLabel;
class QMenu;
class QScrollArea;
class QScrollBar;

class ImageViewer : public QMainWindow
{
    Q_OBJECT

public:
    ImageViewer();
    bool loadFile(const QString &);

private slots:
    void open();

private:
    void createActions();
    void createMenus();

    QLabel *imageLabel;
    QAction *openAct;
    QMenu *fileMenu;
};

#endif

主要:

#include <QApplication>
#include <QCommandLineParser>

#include "imageviewer.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QGuiApplication::setApplicationDisplayName(ImageViewer::tr("Image Viewer"));
    ImageViewer imageViewer;
    imageViewer.show();
    return app.exec();
}

如您所见,视口大小为 570 x 357。我使用的图像是 this(大小为 2560 x 1600,两者的宽高比都差不多是 1.6,太大了,无法在此处上传, 所以会上传图片的截图):

但是当我打开应用程序并在其中添加图像时,我在 QLabel 中获得的图像非常模糊:

如何让标签中的图片和实际图片一样清晰(是bmp格式,所以你必须在[=中的文件打开对话框中将mime类型更改为bmp 46=])?

当我通过 QPainter 执行此任务时,即从图像文件中制作 QImage,然后将其传递给画家并调用 update,效果很好。但是我需要能够在单击时内联缩放图像(我通过在 QLabel 上调用 resize() 来实现),而 QPainter 方式不允许我缩放图像。

平台 - OS X 10.10(视网膜显示屏),Qt 5.3.1,32 位。

您将图像压缩了 4 倍以上 (2560 -> 570),图像中似乎有一些小细节在压缩后无法保留。

实际上,在将图像缩小这么多之后,您或多或少会得到预期的效果。

您 运行 在 Qt 5.3 的 Retina 显示器 Mac 上的 QLabel 中遇到了一个已知错误: https://bugreports.qt.io/browse/QTBUG-42503

从你的图像来看,当你使用 QLabel 时,你似乎只是获得了图像的 non-retina 版本,但如果你在 QPainter 中手动编码,你将获得源的完整分辨率Q图像​​。如果是这样的话,那确实是这个bug造成的。

你有两个解决方案:

  1. 滚动你自己的解决方案,不要使用 QLabel。没有理由不使用 QLabel 就不能轻松 "zoom the image inline"(只需使用自定义 QWidget class 和覆盖的 PaintEvent)。

  2. 升级到已修复此错误的 Qt 版本。无论如何,这可能是正确的解决方案,除非最新版本中有任何回归导致您的应用程序出现问题。根据错误报告,此问题已在 v5.5.0 中修复,因此最新的 v5.5.1 应该可以正常工作。

第一种方法的示例(为简洁起见,我将 header 留在 header 文件中,它非常简单):

void ImageWidget::setImage(QImage image)
{
    //Set the image and invalidate our cached pixmap
    m_image = image;
    m_cachedPixmap = QPixmap();
    update();
}

void ImageWidget::paintEvent(QPaintEvent *)
{
    if ( !m_image.isNull() )
    {
        QSize scaledSize = size() * devicePixelRatio();
        if (m_cachedPixmap.size() != scaledSize)
        {
            QImage scaledImage = m_image.scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
            m_cachedPixmap = QPixmap::fromImage(scaledImage);
            m_cachedPixmap.setDevicePixelRatio(devicePixelRatio());
        }

        QPainter p(this);
        p.drawPixmap(0, 0, m_cachedPixmap);
    }
}

这只是一个非常基本的小部件,它只是将 QImage 绘制到其完整大小,尊重 DevicePixelRatio,因此利用了 Retina 分辨率。注意:在 non-retina 机器上编码,所以我不能保证它在 Retina 上工作,但我从 QLabel 的 Qt 5.5.1 修复中获得了基本实现。与 QLabel 一样,它也缓存 Pixmap,因此它不必 re-scale 每次调用 paintEvent 时,除非小部件实际上已被调整大小。