How to Make an Image Resize to Scale in Qt

How do I make an image resize to scale in Qt?

There are a couple ways to do this, but most of all I would recommend maybe not fighting against the layout system by trying to hint the aspect. As you can see, you are having to try and implement a number methods trying to help the layout.

I can offer two examples. Neither of them use layouts...

The first uses a child QLabel to show the image, and drives its fixed size off of the resize event:

// imagelabel.h

class ImageLabel : public QWidget
{
Q_OBJECT

public:
explicit ImageLabel(QWidget *parent = 0);
const QPixmap* pixmap() const;

public slots:
void setPixmap(const QPixmap&);

protected:
void resizeEvent(QResizeEvent *);

private slots:
void resizeImage();

private:
QLabel *label;
};

// imagelabel.cpp

ImageLabel::ImageLabel(QWidget *parent) :
QWidget(parent)
{
label = new QLabel(this);
label->setScaledContents(true);
label->setFixedSize(0,0);
}

void ImageLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
resizeImage();
}

const QPixmap* ImageLabel::pixmap() const {
return label->pixmap();
}

void ImageLabel::setPixmap (const QPixmap &pixmap){
label->setPixmap(pixmap);
resizeImage();
}

void ImageLabel::resizeImage() {
QSize pixSize = label->pixmap()->size();
pixSize.scale(size(), Qt::KeepAspectRatio);
label->setFixedSize(pixSize);
}

The second example is based off of the answer given by @Arnold_Spence. It is even shorter as it doesn't use a child QLabel. It just draws the pixmap in the paint event:

// imagelabel2.h

class ImageLabel2 : public QWidget
{
Q_OBJECT

public:
explicit ImageLabel2(QWidget *parent = 0);
const QPixmap* pixmap() const;

public slots:
void setPixmap(const QPixmap&);

protected:
void paintEvent(QPaintEvent *);

private:
QPixmap pix;
};

// imagelabel2.cpp

ImageLabel2::ImageLabel2(QWidget *parent) :
QWidget(parent)
{
}

void ImageLabel2::paintEvent(QPaintEvent *event) {
QWidget::paintEvent(event);

if (pix.isNull())
return;

QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);

QSize pixSize = pix.size();
pixSize.scale(event->rect().size(), Qt::KeepAspectRatio);

QPixmap scaledPix = pix.scaled(pixSize,
Qt::KeepAspectRatio,
Qt::SmoothTransformation
);

painter.drawPixmap(QPoint(), scaledPix);

}

const QPixmap* ImageLabel2::pixmap() const {
return &pix;
}

void ImageLabel2::setPixmap (const QPixmap &pixmap){
pix = pixmap;
}

Qt - How to create Image that scale with window, and keeps aspect ratio?

You tagged this question with linux. I develop on Windows 10 - the closest to Linux I have at hand is cygwin. Thus, I solved it in VS2013 but, hey, this is C++ with Qt. It should be portable...

Actually, QPixmap::scaled() has everything built-in what's necessary for scaling by keeping the aspect ratio. Thus, my solution is rather short plugging the QLabel and QPixmap together.

// standard C++ header:
#include <iostream>
#include <string>

// Qt header:
#include <QApplication>
#include <QResizeEvent>
#include <QLabel>
#include <QMainWindow>
#include <QPixmap>
#include <QTimer>

using namespace std;

class LabelImage: public QLabel {

private:
QPixmap _qPixmap, _qPixmapScaled;

public:
void setPixmap(const QPixmap &qPixmap) { setPixmap(qPixmap, size()); }

protected:
virtual void resizeEvent(QResizeEvent *pQEvent);

private:
void setPixmap(const QPixmap &qPixmap, const QSize &size);
};

void LabelImage::resizeEvent(QResizeEvent *pQEvent)
{
QLabel::resizeEvent(pQEvent);
setPixmap(_qPixmap, pQEvent->size());
}

void LabelImage::setPixmap(const QPixmap &qPixmap, const QSize &size)
{
_qPixmap = qPixmap;
_qPixmapScaled = _qPixmap.scaled(size, Qt::KeepAspectRatio);
QLabel::setPixmap(_qPixmapScaled);
}

int main(int argc, char **argv)
{
cout << QT_VERSION_STR << endl;
// main application
#undef qApp // undef macro qApp out of the way
QApplication qApp(argc, argv);
// setup GUI
QMainWindow qWin;
#if 0 // does not consider aspect ratio
QLabel qLblImg;
qLblImg.setScaledContents(true);
#else // (not) 0
LabelImage qLblImg;
#endif // 0
qLblImg.setAlignment(Qt::AlignCenter);
qLblImg.setSizePolicy(
QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
QPixmap qPM;
if (qPM.load("cats.jpg")) qLblImg.setPixmap(qPM);
else {
qLblImg.setText(
QString::fromLatin1("Sorry. Cannot find file 'cats.jpg'."));
}
qWin.setCentralWidget(&qLblImg);
qWin.show();
// run application
return qApp.exec();
}

Notes:

  1. I overloaded the QLabel::setPixmap() method and store actually two versions of the pixmap - the original and the scaled. I'm not sure if this is necessary - it's the first time I used QPixmap.

  2. While reading the Qt docs I found QLabel::setScaledContents(). I gave it a try but it does not consider the aspect ratio of the pixmap. I couldn't find a way to set this as extra option. (May be, I did not search enough. I disabled this code but left it in to remember this as "wrong direction".)

  3. In an intermediate version, I was able to enlarge the application (and scaling was fine) but I could not shrink it. Googling a little bit I found SO: Enable QLabel to shrink even if it truncates text. This solved the issue.

  4. To keep the sample short, I hardcoded the image file name. It is actually unnecessary to say that the current directory of the application must be the one where the file is located. (This is probably no issue in Linux but I had to adjust the debug settings in VS2013 appropriately.)

Below is a snapshot of my test appl.:

Snapshot of testQLabelImage.exe

This should work (of course) with any image file which can be loaded into Qt. However, to make the sample complete (and because Internet and pictures of cats belong really together) I provide the sample image also (for download).

cats.jpg

The left is Max, the right is Moritz. (Or vice versa?)

Edit:

According to the feedback of Shefy Gur-ary, this didn't work properly in a QLayout. Thus, I modified the original version and added a QGridLayout to my sample code to examine this topic:

// standard C++ header:
#include <iostream>
#include <string>

// Qt header:
#include <QApplication>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QMainWindow>
#include <QPixmap>
#include <QResizeEvent>
#include <QTimer>

using namespace std;

class LabelImage: public QLabel {

private:
QPixmap _qPixmap, _qPixmapScaled;

public:
void setPixmap(const QPixmap &qPixmap) { setPixmap(qPixmap, size()); }

protected:
virtual void resizeEvent(QResizeEvent *pQEvent);

private:
void setPixmap(const QPixmap &qPixmap, const QSize &size);
};

void LabelImage::resizeEvent(QResizeEvent *pQEvent)
{
QLabel::resizeEvent(pQEvent);
setPixmap(_qPixmap, pQEvent->size());
}

void LabelImage::setPixmap(const QPixmap &qPixmap, const QSize &size)
{
_qPixmap = qPixmap;
_qPixmapScaled = _qPixmap.scaled(size, Qt::KeepAspectRatio);
QLabel::setPixmap(_qPixmapScaled);
}

int main(int argc, char **argv)
{
cout << QT_VERSION_STR << endl;
// main application
#undef qApp // undef macro qApp out of the way
QApplication qApp(argc, argv);
// setup GUI
QMainWindow qWin;
QGroupBox qBox;
QGridLayout qGrid;
// a macro for the keyboard lazy:
#define Q_LBL_WITH_POS(ROW, COL) \
QLabel qLbl##ROW##COL(QString::fromLatin1(#ROW", "#COL)); \
/*qLbl##ROW##COL.setFrameStyle(QLabel::Raised | QLabel::Box);*/ \
qGrid.addWidget(&qLbl##ROW##COL, ROW, COL, Qt::AlignCenter)
Q_LBL_WITH_POS(0, 0);
Q_LBL_WITH_POS(0, 1);
Q_LBL_WITH_POS(0, 2);
Q_LBL_WITH_POS(1, 0);
LabelImage qLblImg;
qLblImg.setFrameStyle(QLabel::Raised | QLabel::Box);
qLblImg.setAlignment(Qt::AlignCenter);
//qLblImg.setMinimumSize(QSize(1, 1)); // seems to be not necessary
qLblImg.setSizePolicy(
QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
QPixmap qPM;
if (qPM.load("cats.jpg")) qLblImg.setPixmap(qPM);
else {
qLblImg.setText(
QString::fromLatin1("Sorry. Cannot find file 'cats.jpg'."));
}
qGrid.addWidget(&qLblImg, 1, 1, Qt::AlignCenter);
qGrid.setRowStretch(1, 1); // tell QGridLayout to stretch this cell...
qGrid.setColumnStretch(1, 1); // ...prior to other cells (w/ stretch 0)
Q_LBL_WITH_POS(1, 2);
Q_LBL_WITH_POS(2, 0);
Q_LBL_WITH_POS(2, 1);
Q_LBL_WITH_POS(2, 2);
qBox.setLayout(&qGrid);
qWin.setCentralWidget(&qBox);
qWin.show();
// run application
return qApp.exec();
}

Notes:

  1. The aspect ratio of image was still correct but the resizing didn't work anymore. Thus, I added QGrid::setRowStretch() and QGrid::setColumnStretch(). Unfortunately, this didn't change much.

  2. I googled this topic and found SO: Change resize behavior in Qt layouts. Actually, This didn't help really also but made me suspective that the QGridLayout could be the actual source of this layout issue.

  3. For better visualization of this layout issue, I added frames to all my widgets. To my surprise, it worked suddenly.

I assume that the layout in the QGridLayout works somehow not like expected (although I wouldn't dare to call it a bug). However, the workaround to make a frame around the image is something I could live with. (Actually, it looks not that bad.)

A snapshot of the updated code sample:

Snapshot of testQLabelImage.exe (V2.0)

How to scale images in QGraphicsScene? (Qt 5.11)

Use of your windows size in bellow code :

QPixmap scaled_img = image.scaled(this->width(), this->height(), Qt::KeepAspectRatio);

Instead of :

QPixmap scaled_img = image.scaled(img_object->size(), Qt::KeepAspectRatio);

Use of bellows for different aspect ratio :

Sample Image

Resize images inside qt-label

You can try to set the scaledContents property:

self.label.setScaledContents(True)
self.label.setPixmap(QPixmap("your_image.jpeg"))

It works fine for me.

Beware that this scale the image to fill all available space. It means that the aspect ratio of the image wont be preserved unless the label size and the image have the same aspect ratio. You will have the same problem using the QPixmap.scale method as you can see in the images here.

How to resize an image inside QLabel

Assuming you can get the size of your control you can scale your pixmap before you set it in the brush using

pic.scaled ( width, height, Qt::IgnoreAspectRatio, Qt::FastTransformation )

This returns another QPixmap which you can pass to your QBrush.

Just for reference, you can also use a style sheet to set the border image for your control.

border-image: url( yourImage);

How to resize a QImage or QML Image to fit parent container without breaking the Image's aspect ratio

You can use fillMode property.
Like this

fillMode: Image.PreserveAspectFit


Related Topics



Leave a reply



Submit