[graphics/krita] libs/ui/tool: Use KisDisplayColorConverter::convertImageToDisplayColorSpace() for accurate color profile

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

Use KisDisplayColorConverter::convertImageToDisplayColorSpace() for accurate color profile

TODO: Remove caching cause it's getting too slow

M  +11   -5    libs/ui/tool/KisAsyncColorSamplerHelper.cpp
M  +8    -2    libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.cpp
M  +6    -4    libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.h

https://invent.kde.org/graphics/krita/-/commit/3a41164483b0bbae20aaa16479d425fa32cdb522

diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
index a38004d4048..24a970e82bd 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
@@ -676,10 +676,11 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
         zoomDocRectF.setSize(zoomDocRectF.size() / m_d->circleZoomPreviewScale);
         zoomDocRectF.moveCenter(m_d->sampleDocPoint);
 
+        // Returns true if painted or not needed, returns false if painting was deferred
         bool canvasPainted = paintCircleCanvasPreview(cachePainter, cacheRect, zoomDocRectF, tf.map(m_d->cacheCircleInnerClip));
 
-        // canvasPainted is false when canvas preview is not yet available, leave the center hollow for better visual
-        // When draging from the outside (or from ref image only) to canvas, canvasPainted can also be false, causing flickering on the already painted zoom preview
+        // If canvasPainted is false (deferred), leave the center hollow to avoid gray flickering from fill
+        // When draging from the outside to canvas, canvasPainted can go from true (not needed) to false (deferred), causing flickering on the already painted zoom preview
         // So if preview was ever successfully render, don't hide these and cause flickering
         if (canvasPainted || m_d->zoomPreviewHasPainted) {
             paintCircleReferenceImagePreview(cachePainter, cacheRect, zoomDocRectF, tf.map(m_d->cacheCircleInnerClip));
@@ -709,10 +710,15 @@ void KisAsyncColorSamplerHelper::paintCircleCrosshair(QPainter &gc, const QRectF
     qreal luminance = KisPaintingTweaks::luminosityCoarse(currentColor);
     if (luminance < 0.5) crosshairColor = Qt::white;
 
+    qreal dpr = gc.device()->devicePixelRatioF();
+    qreal penWidth = 1.0 * dpr;
+    QPen pen = QPen(crosshairColor, penWidth);
+
     gc.save();
 
+    gc.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
     gc.setCompositionMode(QPainter::CompositionMode_SourceOver);
-    gc.setPen(crosshairColor);
+    gc.setPen(pen);
 
     QTransform tf;
     tf.translate(viewRectF.center().x(), viewRectF.center().y());
@@ -738,7 +744,7 @@ QImage KisAsyncColorSamplerHelper::cacheCanvasImage(QRect &canvasPixelRect) {
     if (m_d->cacheCanvasPreviewRect.isEmpty() || !m_d->cacheCanvasPreviewRect.contains(canvasPixelRect)) {
         // Cache an area larger than the needed preview area to avoid rapid small dynamic allocations
         // And also avoid frequent preview delay from repeatedly fetching canvas image asynchronously
-        qreal cacheScale = 4;
+        qreal cacheScale = 1;
 
         QRect cacheCanvasRect = canvasPixelRect;
         cacheCanvasRect.setSize(canvasPixelRect.size() * cacheScale);
@@ -754,7 +760,7 @@ QImage KisAsyncColorSamplerHelper::cacheCanvasImage(QRect &canvasPixelRect) {
         if (!m_d->canvasPreviewFetchingStarted) {
             m_d->canvasPreviewFetchingStarted = true;
             m_d->strokesFacade()->addJob(m_d->strokeId,
-                new KisColorSamplerStrokeStrategy::GenerateCanvasZoomPreviewData(canvasImage, cacheCanvasRect, canvasImage->colorSpace()->profile()));
+                new KisColorSamplerStrokeStrategy::GenerateCanvasZoomPreviewData(m_d->canvas, cacheCanvasRect, canvasImage->colorSpace()->profile()));
         }
 
         // Return the last valid canvas preview while we wait to fetch new canvas cache async
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 31946545e4e..b3719928b7a 100644
--- a/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.cpp
+++ b/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.cpp
@@ -6,9 +6,10 @@
 
 #include "kis_color_sampler_stroke_strategy.h"
 
+#include "kis_canvas2.h"
+#include "kis_display_color_converter.h"
 #include "kis_tool_utils.h"
 #include "kis_paint_device.h"
-#include "kis_image.h"
 
 struct KisColorSamplerStrokeStrategy::Private
 {
@@ -57,7 +58,12 @@ void KisColorSamplerStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
             Q_EMIT sigFinalColorSelected(*m_d->lastSelectedColor);
         }
     } else if (previewData) {
-        QImage image = previewData->canvasImage->convertToQImage(previewData->canvasPixelRect, previewData->colorProfile);
+        KisPaintDeviceSP dev = previewData->canvas->image()->projection();
+        KisPaintDeviceSP tmp = new KisPaintDevice(dev->colorSpace());
+
+        tmp->makeCloneFromRough(dev, previewData->canvasPixelRect);
+
+        QImage image = previewData->canvas->displayColorConverter()->convertImageToDisplayColorSpace(tmp, previewData->canvasPixelRect, true);
 
         Q_EMIT sigCanvasZoomPreviewUpdated(image, previewData->canvasPixelRect);
     }
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 2de6217b603..bdf761473a1 100644
--- a/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.h
+++ b/libs/ui/tool/strokes/kis_color_sampler_stroke_strategy.h
@@ -12,6 +12,8 @@
 #include "kis_lod_transform.h"
 #include "KoColor.h"
 
+class KisCanvas2;
+
 class KisColorSamplerStrokeStrategy : public QObject, public KisSimpleStrokeStrategy
 {
     Q_OBJECT
@@ -47,16 +49,16 @@ public:
 
     class GenerateCanvasZoomPreviewData : public KisStrokeJobData {
     public:
-        GenerateCanvasZoomPreviewData(KisImageWSP _image, const QRect &_canvasPixelRect, const KoColorProfile *_colorProfile)
-            : canvasImage(_image), canvasPixelRect(_canvasPixelRect), colorProfile(_colorProfile)
+        GenerateCanvasZoomPreviewData(KisCanvas2* _canvas, const QRect &_canvasPixelRect, const KoColorProfile *_colorProfile)
+            : canvas(_canvas), canvasPixelRect(_canvasPixelRect), colorProfile(_colorProfile)
         {}
 
         KisStrokeJobData* createLodClone(int levelOfDetail) override {
             Q_UNUSED(levelOfDetail);
-            return new GenerateCanvasZoomPreviewData(canvasImage, canvasPixelRect, colorProfile);
+            return new GenerateCanvasZoomPreviewData(canvas, canvasPixelRect, colorProfile);
         }
 
-        KisImageWSP canvasImage;
+        KisCanvas2 *canvas;
         QRect canvasPixelRect;
         const KoColorProfile *colorProfile;
     };
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.