Image display control not working well under 6.4.0
-
I have an image display control that appears to be scaling the displayed image in a way that makes it a bit "blocky" compared with 5.15.2. I suspect that somewhere along the way between then and 6.4 the control has changed from using hardware pixels, to using "logical pixels".
Here's how it displays in 5.15.2:
whereas in 6.4.0:
Is there any way to force that control to operate as it did under 5.15.2?
David
-
On a SWAG (simple wild assed guess), I changed the code in my resizeEvent handler that allocated the drawing pixmap to read:
void ImageView::resizeEvent(QResizeEvent* e) { QSize size{ e->size() }; qreal ratio{ devicePixelRatio() }; size *= ratio; m_drawingPixmap = QPixmap(size); m_drawingPixmap.setDevicePixelRatio(ratio); if (nullptr != pPixmap) { drawOnPixmap(); update(); } emit Image_resizeEvent(e); Inherited::resizeEvent(e); }
And that seems to have solved the problem. It's a shame the guy who closed the problem report didn't suggest that.
-
@Perdrix said in Image display control not working well under 6.4.0:
Is there any way to force that control to operate as it did under 5.15.2?
Read again your post and then think by yourself how we should answer your question with the information you gave us.
-
@Perdrix What Christian probably means is for us your post reads "Something draws an image and it doesn't look like I want it".
We need at least some basic information to help you. Start, for example, by explaining what "image display control" is and how it's doing its drawing of the image. Some code of it doing that would be good too if you can share it. -
Without posting the entire source it's a bit hard. Let's see the control is fed a pixmap to display ( pPixmap which a pointer to a photographic image (that is e.g. 5202 x 3464). It is drawn onto a display pixmap (m_drawingPixmap) which is then written to the real screen in the paint mf().
m_drawingPixmap is created thus: m_drawingPixmap = QPixmap{ size() };
Here's drawOnPixmap() with some irrelevant stuff removed:
void ImageView::drawOnPixmap() { QPainter painter(&m_drawingPixmap); QPalette palette{ QGuiApplication::palette() }; QBrush brush{ palette.dark() }; painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.fillRect(rect(), brush); if (nullptr != pPixmap) { const QSize sz = size(); const qreal pixWidth = pPixmap->width(); const qreal pixHeight = pPixmap->height(); const qreal hScale = static_cast<qreal>(sz.width()) / pixWidth; const qreal vScale = static_cast<qreal>(sz.height()) / pixHeight; m_scale = std::min(hScale, vScale); qreal xoffset = 0.0, yoffset = 0.0; if ((pixWidth * m_scale) < sz.width()) { xoffset = floor((sz.width() - (pixWidth * m_scale)) / 2.0); } if ((pixHeight * m_scale) < sz.height()) { yoffset = floor((sz.height() - (pixHeight * m_scale)) / 2.0); } m_origin = QPointF(xoffset, yoffset); displayRect.setTopLeft(m_origin); displayRect.setSize(QSizeF(pixWidth * m_scale, pixHeight * m_scale)); painter.save(); painter.translate(m_origin); painter.scale(m_zoom * m_scale, m_zoom * m_scale); painter.translate(-m_origin); // // Draw the rectangle of interest at the origin location // painter.drawPixmap(m_origin, *pPixmap, rectOfInterest); painter.restore(); : irrelevant stuff removed }
paint() is really simple (with some stuff removed that's not relevant)
void ImageView::paintEvent([[maybe_unused]] QPaintEvent* event) { QPainter painter(this); // // Draw the stuff we drew onto the working pixmap onto the screen // painter.drawPixmap(0, 0, m_drawingPixmap); painter.end() }
Does that clarify?
D. -
Just a guess here, but instead of scaling the painter you could try to draw scaled image i.e. use one of the
drawPixmap
overloads that take the source and target rectangles. -
@Chris-Kawa I tried changing the code in drawOnPixmap to read:
//painter.save(); //painter.translate(m_origin); //painter.scale(m_zoom * m_scale, m_zoom * m_scale); //painter.translate(-m_origin); // // Draw the rectangle of interest at the origin location // //painter.drawPixmap(m_origin, *pPixmap, rectOfInterest); painter.drawPixmap(displayRect, *pPixmap, rectOfInterest); painter.restore();
The results, unfortunately were just as poor:
So there's something rotten in the state of the painter scaling ☹
David -
Lovely! I reported this as a bug and got the "working as designed" response 😦!
https://bugreports.qt.io/browse/QTBUG-107638
Mutter, grumble
-
@Perdrix Since it's a dpi scaling issue you can round the scaling down to an integer value. This should give you the same result as in Qt5, which didn't scale by default. Call QGuiApplication::setHighDpiScaleFactorRoundingPolicy with a floor policy before creating application object.
-
On a SWAG (simple wild assed guess), I changed the code in my resizeEvent handler that allocated the drawing pixmap to read:
void ImageView::resizeEvent(QResizeEvent* e) { QSize size{ e->size() }; qreal ratio{ devicePixelRatio() }; size *= ratio; m_drawingPixmap = QPixmap(size); m_drawingPixmap.setDevicePixelRatio(ratio); if (nullptr != pPixmap) { drawOnPixmap(); update(); } emit Image_resizeEvent(e); Inherited::resizeEvent(e); }
And that seems to have solved the problem. It's a shame the guy who closed the problem report didn't suggest that.