简体   繁体   中英

QLabel with pixmap image getting blurred

I have an image which I need to display as the background of a QLabel . This is my code (culled from Qt documentation 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);

}

Header file:

#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

Main:

#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();
}

As you can see, the viewport size is 570 by 357. The image I am using is this (size is 2560 by 1600, both have an aspect ratio of almost 1.6, too big to upload here, so will upload a screenshot of the pic):

在此处输入图片说明

But when I open the app and add the image there, the image I get in the QLabel is pretty blurred:

在此处输入图片说明

How do I make the image in the label as well defined as the actual image (it is in bmp format, so you have to change the mime type to bmp in the file open dialog in Mac)?

When I do this task through QPainter , ie making a QImage out of the image file, then passing it to the painter and calling update it comes up fine. But I need to be able to zoom the image inline when clicked (which I am doing by calling resize() on the QLabel ), and the QPainter way does not let me zoom the image.

Platform - OS X 10.10 (Retina Display), Qt 5.3.1, 32 bit.

You are running into a known bug in QLabel on a Retina display Mac in Qt 5.3: https://bugreports.qt.io/browse/QTBUG-42503

From your image, it looks like you are simply getting a non-retina version of your image when you use QLabel, but if you code it manually in the QPainter you're getting the full resolution of your source QImage. If thats the case, then this is indeed caused by this bug.

You have two solutions:

  1. Roll your own solution, don't use QLabel. There is no reason you can't easily "zoom the image inline" without using QLabel (just use a custom QWidget class with an overrided PaintEvent).

  2. Upgrade to a version of Qt where this bug has been fixed. This is probably the right solution anyway, unless there are any regressions in the latest version that cause a problem in your application. According to the bug report, this issues was fixed in v5.5.0, so the latest v5.5.1 should work fine.

An example of the first approach (I'll leave the header out the header file for brevity, its pretty simple):

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);
    }
}

This is simply a very basic widget that just draws a QImage to its full size, respecting the DevicePixelRatio, and hence taking advantage of Retina resolution. Note: coded this on a non-retina machine, so I can't guarantee that it works on Retina, but I got the basic implementation from the Qt 5.5.1 fix for QLabel. Like QLabel, it also caches the Pixmap so it doesn't have to re-scale every time paintEvent is called, unless the widget has actually been resized.

You compress the image more than 4-fold (2560 -> 570) and it seems there are small details in the image impossible to retain after shriking this much.

Actually, you get more or less what you can expect after shrinking an image so much.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM