QLabel与pixmap图像变得模糊

时间:2015-11-02 17:40:05

标签: c++ macos qt qpixmap qlabel

我有一张图片需要显示为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乘357.我使用的图像是this(大小是2560乘1600,两者的宽高比几乎都是1.6,太大了,无法在这里上传,所以将上传图片的截图:

enter image description here

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

enter image description here

如何使标签中的图像定义为实际图像(它是bmp格式,因此您必须在Mac中的文件打开对话框中将mime类型更改为bmp?< / p>

当我通过QPainter执行此任务时,即从图像文件中取出QImage,然后将其传递给画家并调用update它就可以了。但是我需要能够在点击时内联缩放图像(我正在resize()上调用QLabel),而QPainter方式不允许我缩放图像。

平台 - OS X 10.10(Retina显示),Qt 5.3.1,32位。

2 个答案:

答案 0 :(得分:2)

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

从您的图像来看,当您使用QLabel时,看起来您只是获得图像的非视网膜版本,但如果您在QPainter中手动编码,则您将获得源QImage的完整分辨率。如果是这样的话,那确实是由这个错误引起的。

您有两种解决方案:

  1. 滚动您自己的解决方案,不要使用QLabel。没有理由你不能在不使用QLabel的情况下轻松“缩放图像内联”(只需使用带有覆盖的PaintEvent的自定义QWidget类)。

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

  3. 第一种方法的一个例子(为了简洁,我会将标题保留在头文件中,非常简单):

    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分辨率。注意:在非视网膜机器上编码,所以我不能保证它适用于Retina,但我从Qt 5.5.1修复了QLabel的基本实现。与QLabel一样,它也会缓存Pixmap,因此每次调用paintEvent时都不必重新缩放,除非实际调整了窗口小部件的大小。

答案 1 :(得分:0)

你压缩图像的次数超过4倍(2560 - > 570),看起来图像中的小细节在肆无忌惮之后无法保留。

实际上,在缩小图像之后,你会得到更多或更少的东西。