[graphics/krita] libs/ui/tool/strokes: Fix off center preview in instant preview mode

Emmet O'Neill <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit b0bcdb8c0e9c0aa485f07f841b216a899c8a8be4 by Emmet O'Neill, on behalf of Dat Le.
Committed on 13/08/2026 at 23:16.
Pushed by emmetoneill into branch 'master'.

Fix off center preview in instant preview mode

M  +4    -4    libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.cpp
M  +22   -2    libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.h

https://invent.kde.org/graphics/krita/-/commit/b0bcdb8c0e9c0aa485f07f841b216a899c8a8be4

diff --git a/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.cpp b/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.cpp
index d60f92eaf10..095b25b0708 100644
--- a/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.cpp
+++ b/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.cpp
@@ -69,13 +69,13 @@ void KisColorSamplerStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
 
         QImage image = previewData->colorConverter->convertImageToDisplayColorSpace(tmpDev, effectiveRect, true);
 
+        // In case of instant preview, scale the sample back up to fit the original requested rect
         if (previewData->levelOfDetail > 0) {
-            KisLodTransform transform(previewData->levelOfDetail);
-            qreal scale = transform.lodToInvScale(previewData->levelOfDetail);
+            if (!previewData->originalRect.isValid()) return;
 
-            image = image.scaled(QSize(scale * image.width(), scale * image.height()));
+            image = image.scaled(previewData->originalRect.size());
 
-            effectiveRect = transform.mapInverted(effectiveRect);
+            effectiveRect = QRect(QPoint(0,0), previewData->originalRect.size());
         }
 
         Q_EMIT sigCanvasZoomPreviewUpdated(image, effectiveRect);
diff --git a/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.h b/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.h
index 00011c71604..4990ed8c0e9 100644
--- a/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.h
+++ b/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.h
@@ -51,17 +51,32 @@ public:
     public:
         GenerateCanvasZoomPreviewData(KisPaintDeviceSP _canvasDev, const QRect &_canvasPixelRect, KisDisplayColorConverter *_colorConverter,
                                       int _levelOfDetail = 0, QSharedPointer<boost::none_t> _cookie = nullptr)
-            : canvasDev(_canvasDev), canvasPixelRect(_canvasPixelRect), colorConverter(_colorConverter), levelOfDetail(_levelOfDetail), strokeCookie(_cookie)
+            : canvasDev(_canvasDev), canvasPixelRect(_canvasPixelRect), colorConverter(_colorConverter),
+            levelOfDetail(_levelOfDetail), strokeCookie(_cookie), originalRect()
         {}
 
         KisStrokeJobData* createLodClone(int levelOfDetail) override {
             KisLodTransform transform(levelOfDetail);
+
             QRect lodPixelRect = transform.map(canvasPixelRect);
+
+            // The LOD pixel rect size should be odd so that the pixel sampled is in the center
+            // Otherwise, even after scaling back, it will be wrong
+            if (lodPixelRect.width() % 2 == 0) {
+                int oddSize = lodPixelRect.width() - 1;
+                if (oddSize < 3) oddSize = 3;
+                lodPixelRect.setSize(QSize(oddSize, oddSize));
+            }
+            lodPixelRect.moveCenter(transform.map(canvasPixelRect.center()));
+
             GenerateCanvasZoomPreviewData *newData =
                 new GenerateCanvasZoomPreviewData(canvasDev, lodPixelRect, colorConverter, levelOfDetail);
+
             // When Lod is involved, swap the cookie to the new Lod clone to track execution
             // The original object seems to leaks
-            newData->strokeCookie.swap(strokeCookie);
+            newData->swapCookie(strokeCookie);
+
+            newData->originalRect = canvasPixelRect;
 
             return newData;
         }
@@ -71,11 +86,16 @@ public:
             return strokeCookie;
         }
 
+        void swapCookie(QSharedPointer<boost::none_t> &newCookie) {
+            strokeCookie.swap(newCookie);
+        }
+
         KisPaintDeviceSP canvasDev;
         QRect canvasPixelRect;
         KisDisplayColorConverter *colorConverter;
         int levelOfDetail;
         QSharedPointer<boost::none_t> strokeCookie;
+        QRect originalRect;
     };
 public:
     KisColorSamplerStrokeStrategy(int radius, int blend, int lod = 0);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.