Qpainter scale pixmap to parent with aspect ratio
-
@pauledd
i suggest to cache the pixmap upon widget resize and just paint it in the paintEvent().void VideoFrame::resizeEvent(QResizeEvent* event) { const QSize size = event->size(); m_CachedPixmap = size.height() < size.width() ? m_Pixmap.scaledToHeight(size.height(), Qt::SmoothTransformation) : m_Pixmap.scaledToWidth(size.width(), Qt::SmoothTransformation); this->update(); QWidget::resizeEvent(event); } void VideoFrame::paintEvent(QPaintEvent *) { ... const QSize pixSIze = m_CachedPixmap.size(); const int x = (this->rect().width() - pixSize .width()) / 2.0; const int y = (this->rect().height() - pixSize .height()) / 2.0; painter.drawPixmap(x,y, pixSize.width(), pixSIze .height(), m_CachedPixmap); ... }
(untested)
-
void VideoFrame::paintEvent(QPaintEvent *) { QPainter painter(this); QSize widgetSize = rect().size(); const QPixmap paintPixmap(QStringLiteral("image_320.png")); const auto newHeight = widgetSize.width()*paintPixmap.height()/paintPixmap.width(); if(newHeight<=widgetSize.height()) widgetSize.setHeight(newHeight); else widgetSize.setWidth(widgetSize.height()*paintPixmap.width()/paintPixmap.height()); style()->drawItemPixmap(&painter,rect(),Qt::AlignCenter,paintPixmap.scaled(widgetSize)); }
-
thanks to you both :)
@raven-worx
I tried your code but the image "plopps" strangely and gets bigger than the frame for a short time...
Why caching the pixmap? Did you do this for performance reasons?@VRonin
Your code worked flawlessly.I will later replace the image file again with a pointer to an QImage that gets updated at 9fps (thermal camera source) so @VRonin solution "feels" better for now, because I dont know how this caching the image while resize will impact my livestream...
-
@pauledd said in Qpainter scale pixmap to parent with aspect ratio:
I tried your code but the image "plopps" strangely and gets bigger than the frame for a short time...
as stated its untested, and straight out of my head. But i guess i'ts just a minor mistake in the calculation.
Why caching the pixmap? Did you do this for performance reasons?
yes, because there is no need to load a pixmap from file in every paintEvent() call!
-
@raven-worx said in Qpainter scale pixmap to parent with aspect ratio:
yes, because there is no need to load a pixmap from file in every paintEvent() call!
Okay but later I will use this:
bool VideoFrame::startCam() { ... for(int i=0;i<img->height();i++) { memcpy(img->scanLine(i), frame1.row(i).data, img->bytesPerLine()); } update(); ... } ... void VideoFrame::paintEvent(QPaintEvent *) { ... const QPixmap paintPixmap(QPixmap::fromImage(*img)); ... }
I have camera data from frame1 that is constantly copied to "img" and then drawed in the paintEvent... would that caching make then sense too? I used the static image just as placeholder to demonstrate...
@VRonin
I got a new problem with your code.. how can I then rotate the rect/image around its centerpoint. If I simply rotate the painter the centerpoint lays in the upper left corner. I then tried to translate the painter to half of the image dimensions and then tried painter.rotate but with your code that doesnt work anymore, can you give me a hint how to solve that? -
@pauledd said in Qpainter scale pixmap to parent with aspect ratio:
I have camera data from frame1 that is constantly copied to "img" and then drawed in the paintEvent... would that caching make then sense too?
basically yes, since you do not know how often the paintEvent() will be called until the next image is received.
And also btw, it's not necessary to convert the QImage to a QPixmap just for drawing. QPainter also provides methods to draw a QImage directly.
-
@pauledd said in Qpainter scale pixmap to parent with aspect ratio:
how can I then rotate the rect/image around its centerpoint.
Do not rotate the painter, rotate the pixmap.
QPainter painter(this); QSize widgetSize = rect().size(); QPixmap paintPixmap(QStringLiteral("image_320.png")); QTransform rotateTransform; rotateTransform.rotate(45); paintPixmap=paintPixmap.transformed(rotateTransform); const auto newHeight = widgetSize.width()*paintPixmap.height()/paintPixmap.width(); if(newHeight<=widgetSize.height()) widgetSize.setHeight(newHeight); else widgetSize.setWidth(widgetSize.height()*paintPixmap.width()/paintPixmap.height()); style()->drawItemPixmap(&painter,rect(),Qt::AlignCenter,paintPixmap.scaled(widgetSize));
Caching does makes a lot of sense, you can use QPixmapCache
@raven-worx said in Qpainter scale pixmap to parent with aspect ratio:
QPainter also provides methods to draw a QImage directly.
Yes but:
- it just calls
QPixmap::fromImage
internally: https://code.woboq.org/qt5/qtbase/src/gui/painting/qpaintengine.cpp.html#625 QStyle
doesn't have it
- it just calls
-
@VRonin I dont yet get behind the way you draw the pixmap in your code.
you use (still noob beginner ;) ):style()->drawItemPixmap(&painter,rect(),Qt::AlignCenter,paintPixmap.scaled(widgetSize));
I've never seen such a style()-> ... alone without an object... it seems to be not declared somewhere, to what does it refer to? To the Qpainter?
The same is with the:
QSize widgetSize = rect().size();
rect().size(); refers to the QFrame? I usually would expext an "this.rect().size();"
And that brings me to another question. If I need to draw an ellipse, as I did
previously with painter.drawEllipse, into that image area, for example at position 40,40 seen from top/left and staying at that point while rotating with the image how would that fit into your way to draw with:style()->drawItem...
or is that not possible?
-
Hi
style()
refers to the QWidget member method that returns the active
QStyle.
It would be the same as this->Style().
Same with
rect().size();
also means this-> rect().size();
They are defined in the base class. ( QWidget ) -
@pauledd said in Qpainter scale pixmap to parent with aspect ratio:
I usually would expext an "this.rect().size();"
Do you come from python? it is
this->rect()
andthis->style()
but in C++ you don't need to explicitly usethis
in front.to what does it refer to? To the Qpainter?
http://doc.qt.io/qt-5/qwidget.html#style
@pauledd said in Qpainter scale pixmap to parent with aspect ratio:
If I need to draw an ellipse, as I did
QStyle
/QStylePainter
is an abstraction over the drawing of controls, it does not provide drawing of basics like lines and circles. See http://doc.qt.io/qt-5/qstyle.html#developing-style-aware-custom-widgets -
@pauledd said in Qpainter scale pixmap to parent with aspect ratio:
I will paint an ellipse as png
Saving and loading to png file format is expensive, I would advise against it.
If the position of the ellipsis doesn't change in the pixmap then draw it using
QPainter
on the pixmap and cache it. If the ellipsis is dynamic then paint it directly on the widget from thepaintEvent
-
Ok, I will try that...
Maybe I should have been more clearly what I intend to get...
I had it all working already, just without the scaling issueI get camera images and I let opencv compute min/max values and a centerpoint. Somethimes the camera is rotated in a undesired position so the user should be able to rotate the view, including the measurepoints, and more complex including the point values so that the stay at the points but do not rotate staying readable...
I keep trying with qpainter draw