I am trying to write a Qt-based application that displays and manipulates images.
I want the image to be always expanded to the size of the window keeping its aspect ratio. Unfortunately QLabel does not have an option to keep aspect ratio of the attached pixmap. So I wrote a custom widget and implemented resizeEvent() and paintEvent() to resize the image and paint it: class MyLabel : public QWidget
{
Q_Object
public:
MyLabel(): pixmap("test.tif") {}
protected:
void resizeEvent(QResizeEvent *event)
{
pixmap_scaled = pixmap.scaled(size(), Qt::KeepAspectRatio);
}
void paintEvent(QPaintEvent *event)
{
QPainter p(this);
p.drawPixmap(0, 0, pixmap_scaled);
p.end();
}
开发者_C百科private:
QPixmap pixmap, pixmap_scaled;
};
But the image was not resized as smoothly as QLabel does.
Then I take a look at the paintEvent function of QLabel in qlabel.cpp to see how it displays the pixmap.
There it seems that the pixmap is once converted to a QImage and scaled to the window size, and then converted again to a QPixmap. I was a bit surprised because converting between QPixmap and QImage is an expensive operation according to Qt reference manual, but I tried rewriting paintEvent() of my widget to do the same thing as QLabel::paintEvent(). Then the resizing became much slower as expected.I wonder why resizing of QLabel is so fast. Is it the benefit of "implicit data sharing"?
Of course It is impossible to just copy paintEvent() of QLabel to my class because private data such as "d pointer" cannot be accessed.Any help would be appreciated.
A couple of general observations that may help.
- If you convert to the QImage once and keep a reference to the QImage, that will likely improve performance some. You would then only need to scale and convert back in the paint event.
- In the resize event, mark that the image needs to be rescaled, but don't do it until you paint. Qt will combine paint events when it can, and this way you avoid scaling, just to scale again before painting.
- Consider finding "steps", and keeping cached images there if you often size both up and down. Show those steps when possible, and choose a step that scales nicely (usually by multiples of 2) for the current size when not possible.
- Consider not scaling the image directly, but using a painter transform instead. This might offload the scaling work from the CPU to a GPU transform, which will often be faster. In this situation, you'd always want to draw the image full-size, and let the transform go up or down.
From QPixmap detailed description:
QImage is designed and optimized for I/O, and for direct pixel access and manipulation, while QPixmap is designed and optimized for showing images on screen.
So I guess that it's faster to scale QImage and convert it back to QPixmap, than scaling QPixmap
精彩评论