easymodo / qimgv

Image viewer. Fast, easy to use. Optional video support.
GNU General Public License v3.0
2.3k stars 160 forks source link

Image has wrong scale with multiple monitors in different scale #518

Open jerome-cui opened 9 months ago

jerome-cui commented 9 months ago

I have my primary monitor scale at 150%, and the external monitor scale at 100%. Then qimgv will display image at wrong scale in the external monitor and not fill the window, just like below: Screenshot_20231011_143012

System info:

OS: Kubuntu 23.04 Graphis platform: Wayland KDE plasma: 5.27.8 Primary monitor: 3072 1920, 150% External monitor: 1920 1080, 100% Image size: 6885 * 4534

jerome-cui commented 9 months ago

It is caused by the fixed dpr in ImageViewerV2, which the value is from the primary monitor. I fixed this issue with the following code updates:

diff --git a/qimgv/gui/viewers/imageviewerv2.cpp b/qimgv/gui/viewers/imageviewerv2.cpp
index 2bf906cd..571c5cfb 100644
--- a/qimgv/gui/viewers/imageviewerv2.cpp
+++ b/qimgv/gui/viewers/imageviewerv2.cpp
@@ -31,7 +31,7 @@ ImageViewerV2::ImageViewerV2(QWidget *parent) : QGraphicsView(parent),
     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
     setAcceptDrops(false);

-    dpr = this->devicePixelRatioF();
+    // dpr = this->devicePixelRatioF();
     hs = horizontalScrollBar();
     vs = verticalScrollBar();

@@ -235,7 +235,7 @@ bool ImageViewerV2::showAnimationFrame(int frame) {

 void ImageViewerV2::updatePixmap(std::unique_ptr<QPixmap> newPixmap) {
     pixmap = std::move(newPixmap);
-    pixmap->setDevicePixelRatio(dpr);
+    pixmap->setDevicePixelRatio(this->devicePixelRatioF());
     pixmapItem.setPixmap(*pixmap);
     pixmapItem.show();
     pixmapItem.update();
@@ -276,7 +276,7 @@ void ImageViewerV2::showImage(std::unique_ptr<QPixmap> _pixmap) {
     if(_pixmap) {
         pixmapItemScaled.hide();
         pixmap = std::move(_pixmap);
-        pixmap->setDevicePixelRatio(dpr);
+        pixmap->setDevicePixelRatio(this->devicePixelRatioF());
         pixmapItem.setPixmap(*pixmap);
         Qt::TransformationMode mode = Qt::SmoothTransformation;
         if(mScalingFilter == QI_FILTER_NEAREST)
@@ -323,11 +323,11 @@ void ImageViewerV2::closeImage() {
 }

 void ImageViewerV2::setScaledPixmap(std::unique_ptr<QPixmap> newFrame) {
-    if(!movie && newFrame->size() != scaledSizeR() * dpr)
+    if(!movie && newFrame->size() != scaledSizeR() * this->devicePixelRatioF())
         return;

     pixmapScaled = std::move(newFrame);
-    pixmapScaled->setDevicePixelRatio(dpr);
+    pixmapScaled->setDevicePixelRatio(this->devicePixelRatioF());
     pixmapItemScaled.setPixmap(*pixmapScaled);
     pixmapItem.hide();
     pixmapItemScaled.show();
@@ -433,7 +433,7 @@ void ImageViewerV2::requestScaling() {
     // request "real" scaling when graphicsscene scaling is insufficient
     // (it uses a single pass bilinear which is sharp but produces artifacts on low zoom levels)
     if(currentScale() < FAST_SCALE_THRESHOLD)
-        emit scalingRequested(scaledSizeR() * dpr, mScalingFilter);
+        emit scalingRequested(scaledSizeR() * this->devicePixelRatioF(), mScalingFilter);
 }

 bool ImageViewerV2::imageFits() const {
@@ -517,7 +517,7 @@ void ImageViewerV2::mouseMoveEvent(QMouseEvent *event) {
     } else if(event->buttons() & Qt::RightButton) {
         // ------------------- ZOOM ----------------------
         // filter out possible mouse jitter by ignoring low delta drags
-        if(mouseInteraction == MouseInteractionState::MOUSE_ZOOM || abs(mousePressPos.y() - event->pos().y()) > zoomThreshold / dpr) {
+        if(mouseInteraction == MouseInteractionState::MOUSE_ZOOM || abs(mousePressPos.y() - event->pos().y()) > zoomThreshold / this->devicePixelRatioF()) {
             if(cursor().shape() != Qt::SizeVerCursor) {
                 setCursor(Qt::SizeVerCursor);
             }
@@ -677,7 +677,7 @@ void ImageViewerV2::mouseMoveZoom(QMouseEvent *event) {
     float stepMultiplier = 0.003f; // this one feels ok
     int currentPos = event->pos().y();
     int moveDistance = mouseMoveStartPos.y() - currentPos;
-    float newScale = currentScale() * (1.0f + stepMultiplier * moveDistance * dpr);
+    float newScale = currentScale() * (1.0f + stepMultiplier * moveDistance * this->devicePixelRatioF());
     mouseMoveStartPos = event->pos();
     imageFitMode = FIT_FREE;
drocheam commented 5 months ago

If I remember correctly, different scales between monitors aren't supported by X11, so this only affects Wayland.

Until this is fixed qimgv can also be run with enforced usage of X11:

env QT_QPA_PLATFORM=xcb qimgv

Also see https://wiki.archlinux.org/title/Wayland#Qt.

Or just add the environment variable QT_QPA_PLATFORM=xcb to the .desktop entry.