[graphics/krita] libs/ui/tool: Refractor canvas and reference image preview painting

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

Refractor canvas and reference image preview painting

M  +68   -58   libs/ui/tool/KisAsyncColorSamplerHelper.cpp
M  +4    -0    libs/ui/tool/KisAsyncColorSamplerHelper.h

https://invent.kde.org/graphics/krita/-/commit/089f875a83fb5565be16052090c093f3f25e70f5

diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
index 67906023ccb..a9e9c4d9c01 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
@@ -70,7 +70,7 @@ struct KisAsyncColorSamplerHelper::Private
     bool circlePreviewExtraCircles {true};
     qreal circleZoomPreviewScale {2};
     QRectF previewDocRect;
-    QPainterPath cacheInnerPath;
+    QPainterPath cacheCircleInnerClip;
 
     QColor currentColor;
     QColor baseColor;
@@ -521,7 +521,7 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
         QPainterPath innerPath;
         innerPath.addPath(innerEllipse);
 
-        m_d->cacheInnerPath = innerPath;
+        m_d->cacheCircleInnerClip = innerPath;
 
         if (m_d->circlePreviewThickness < 0.5 && m_d->circlePreviewExtraCircles) {
             qreal extraMargin = 0.1*m_d->circlePreviewThickness*innerRect.width(); // looks better
@@ -540,82 +540,92 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
     // TODO: Check why zoom still show after leaving canvas
     cachePainter.setPen(Qt::NoPen);
     cachePainter.setCompositionMode(QPainter::CompositionMode_Clear);
-    cachePainter.drawPath(tf.map(m_d->cacheInnerPath));
+    cachePainter.drawPath(tf.map(m_d->cacheCircleInnerClip));
 
+    bool didDrawRefImage = false;
+
+    paintCircleCanvasPreview(cachePainter, cacheRect, tf.map(m_d->cacheCircleInnerClip));
+
+    // Draw inner circle outline if enabled
+    if (m_d->circlePreviewOutlineEnabled) {
+        cachePainter.setBrush(Qt::transparent);
+        cachePainter.setPen(pen);
+        cachePainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+        cachePainter.drawPath(tf.map(m_d->cacheCircleInnerClip));
+    }
+
+    gc.drawPixmap(viewRectF.toRect(), m_d->cache);
+
+    gc.restore();
+}
+
+void KisAsyncColorSamplerHelper::paintCircleCanvasPreview(QPainter &gc, const QRectF &viewRectF, const QPainterPath &clip) {
     QRectF sampleDocRectF = m_d->previewDocRect;
-    sampleDocRectF.setHeight(sampleDocRectF.height() / m_d->circleZoomPreviewScale);
-    sampleDocRectF.setWidth(sampleDocRectF.width() / m_d->circleZoomPreviewScale);
+    sampleDocRectF.setSize(sampleDocRectF.size() / m_d->circleZoomPreviewScale);
     sampleDocRectF.moveCenter(m_d->previewDocRect.center());
+
     QRectF canvasSampleRectF = m_d->canvas->image()->documentToPixel(sampleDocRectF);
 
-    dbgUI << "View rect: " << viewRectF;
     dbgUI << "Preview doc rect: " << m_d->previewDocRect;
     dbgUI << "Sample doc rect: " << sampleDocRectF;
     dbgUI << "Canvas sample rect: " << canvasSampleRectF;
     dbgUI << "Sample doc point: " << sampleDocRectF.center();
 
-    QImage cacheCanvasImage;
-    bool sampledRefImage = false;
+    // Copy a piece of canvas image with size = (previewDocRect size) / (zoom preview scale)
+    QImage canvasPreview = m_d->canvas->image()->convertToQImage(canvasSampleRectF.toRect(), nullptr);
+    gc.setCompositionMode(QPainter::CompositionMode_SourceOver);
+
+    gc.setClipPath(clip);
 
+    // QtDoc: The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
+    // Since the piece of canvas is (zoom preview scale) times smaller than cacheRect
+    // drawImage will scale it up that many times, thus achieving the zoom effect
+    gc.drawImage(viewRectF, canvasPreview);
+
+    gc.setClipPath(QPainterPath(), Qt::NoClip);
+}
+
+void KisAsyncColorSamplerHelper::paintCircleReferenceImagePreview(QPainter &gc, const QRectF &viewRectF, const QPainterPath &clip) {
+    gc.setCompositionMode(QPainter::CompositionMode_SourceOver);
     // Check if doc coord is on canvas or reference image
     KisDocument *doc = m_d->canvas->viewManager()->document();
-    if (doc) {
-        KisReferenceImagesLayerSP refLayer = doc->referenceImagesLayer();
-        if (refLayer) {
-            for(int i=0;i<refLayer->referenceImages().count();i++) {
-                KisReferenceImage *refImage = refLayer->referenceImages().at(i);
-                QPolygonF outline = refImage->outline().toFillPolygon().translated(refImage->position());
-                if (outline.containsPoint(sampleDocRectF.center(), Qt::OddEvenFill)) {
-                    dbgUI << "Sampling on reference image no " << i;
-                    // TODO: Figure out how to convert shape coordinate to pixel coordinate
-                    // Just need to divide by scale. How to find the scale though
-                    QImage image = refImage->getImage();
-                    qreal xScale = refImage->boundingRect().width() / image.width();
-                    qreal yScale = refImage->boundingRect().height() / image.height();
-                    QRectF refRectF = refImage->documentToShape(sampleDocRectF);
-                    dbgUI << "Shape coordinate: " << refRectF;
-                    dbgUI << "Image scaling: " << refImage->transformation().m11();
-                    QPointF topLeft = refRectF.topLeft();
-                    topLeft.setX(topLeft.x() / xScale);
-                    topLeft.setY(topLeft.y() / yScale);
-                    QPointF bottomRight = refRectF.bottomRight();
-                    bottomRight.setX(bottomRight.x() / xScale);
-                    bottomRight.setY(bottomRight.y() / yScale);
-
-                    dbgUI << "Shape pixel coordinate: " << QRectF(topLeft, bottomRight);
-
-                    cacheCanvasImage = refImage->getImage().copy(QRectF(topLeft, bottomRight).toRect());
-                    sampledRefImage = true;
-                }
-            }
-        }
-    }
+    if (!doc) return;
+    KisReferenceImagesLayerSP refLayer = doc->referenceImagesLayer();
+    if (!refLayer) return;
 
-    if (!sampledRefImage)
-        // Copy a piece of canvas image with size = (previewDocRect size) / (zoom preview scale)
-        cacheCanvasImage = m_d->canvas->image()->convertToQImage(canvasSampleRectF.toRect(), nullptr);
+    QRectF sampleDocRectF = m_d->previewDocRect;
+    sampleDocRectF.setSize(sampleDocRectF.size() / m_d->circleZoomPreviewScale);
+    sampleDocRectF.moveCenter(m_d->previewDocRect.center());
 
-    cachePainter.setClipPath(tf.map(m_d->cacheInnerPath));
-    cachePainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+    for(int i=0;i<refLayer->referenceImages().count();i++) {
+        KisReferenceImage *refImage = refLayer->referenceImages().at(i);
+        QPolygonF outline = refImage->outline().toFillPolygon().translated(refImage->position());
+        if (!outline.containsPoint(sampleDocRectF.center(), Qt::OddEvenFill)) continue;
 
-    // QtDoc: The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
-    // Since the piece of canvas is (zoom preview scale) times smaller than cacheRect
-    // drawImage will scale it up that many times, thus achieving the zoom effect
-    cachePainter.drawImage(cacheRect, cacheCanvasImage);
+        dbgUI << "Sampling on reference image no " << i;
 
-    cachePainter.setClipPath(QPainterPath(), Qt::NoClip);
+        QImage image = refImage->getImage();
+        qreal xScale = refImage->boundingRect().width() / image.width();
+        qreal yScale = refImage->boundingRect().height() / image.height();
+        QRectF refRectF = refImage->documentToShape(sampleDocRectF);
 
-    // Draw inner circle outline if enabled
-    if (m_d->circlePreviewOutlineEnabled) {
-        cachePainter.setBrush(Qt::transparent);
-        cachePainter.setPen(pen);
-        cachePainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
-        cachePainter.drawPath(tf.map(m_d->cacheInnerPath));
-    }
+        dbgUI << "Shape coordinate: " << refRectF;
+        dbgUI << "Image scaling: " << refImage->transformation().m11();
 
-    gc.drawPixmap(viewRectF.toRect(), m_d->cache);
+        QPointF topLeft = refRectF.topLeft();
+        topLeft.setX(topLeft.x() / xScale);
+        topLeft.setY(topLeft.y() / yScale);
+        QPointF bottomRight = refRectF.bottomRight();
+        bottomRight.setX(bottomRight.x() / xScale);
+        bottomRight.setY(bottomRight.y() / yScale);
 
-    gc.restore();
+        dbgUI << "Shape pixel coordinate: " << QRectF(topLeft, bottomRight);
+
+        QImage refPreview = refImage->getImage().copy(QRectF(topLeft, bottomRight).toRect());
+        refPreview.convertTo(QImage::Format_ARGB32);
+
+        gc.drawImage(viewRectF, refPreview);
+    }
 }
 
 void KisAsyncColorSamplerHelper::slotAddSamplingJob(const QPointF &docPoint)
diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.h b/libs/ui/tool/KisAsyncColorSamplerHelper.h
index 1a7d3c1e8d5..88d680ad581 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.h
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.h
@@ -15,6 +15,7 @@
 #include "kis_types.h"
 
 class QPainter;
+class QPainterPath;
 class KoViewConverter;
 class KisStrokesFacade;
 class KisCanvas2;
@@ -80,6 +81,9 @@ private:
     void paintRectangle(QPainter &gc, const QRectF &viewRectF, const QColor &currentColor, const QColor &baseColor);
     void paintCircle(QPainter &gc, const QRectF &viewRectF, const QColor &currentColor, const QColor &baseColor);
 
+    void paintCircleCanvasPreview(QPainter &gc, const QRectF &viewRectF, const QPainterPath &clip);
+    void paintCircleReferenceImagePreview(QPainter &gc, const QRectF &viewRectF, const QPainterPath &clip);
+
     struct Private;
     QScopedPointer<Private> m_d;
 };
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.