[graphics/krita] libs/ui/tool: Fix reference image preview transparancy, more refractor

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

Fix reference image preview transparancy, more refractor

M  +43   -49   libs/ui/tool/KisAsyncColorSamplerHelper.cpp
M  +3    -2    libs/ui/tool/KisAsyncColorSamplerHelper.h

https://invent.kde.org/graphics/krita/-/commit/50768ddc7c07af4e2d38780fa429269b3e9dae68

diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
index a9e9c4d9c01..a08c5563616 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
@@ -521,8 +521,6 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
         QPainterPath innerPath;
         innerPath.addPath(innerEllipse);
 
-        m_d->cacheCircleInnerClip = innerPath;
-
         if (m_d->circlePreviewThickness < 0.5 && m_d->circlePreviewExtraCircles) {
             qreal extraMargin = 0.1*m_d->circlePreviewThickness*innerRect.width(); // looks better
             QPointF leftCenter = QPointF(innerRect.left() - extraMargin, innerRect.top() + innerRect.height()/2.0);
@@ -534,24 +532,33 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
 
             innerPath = innerPath.intersected(innerEllipse);
         }
+
+        m_d->cacheCircleInnerClip = innerPath;
+
+        // 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));
+        }
     }
 
-    // When sampler leave the canvas, cache won't update so always need to clear the center
-    // TODO: Check why zoom still show after leaving canvas
+    // Always need to clear the center because canvas preview is set to DestinationOver
     cachePainter.setPen(Qt::NoPen);
+    // If the cached block don't run, no brush is set. So set it
+    cachePainter.setBrush(Qt::transparent);
     cachePainter.setCompositionMode(QPainter::CompositionMode_Clear);
     cachePainter.drawPath(tf.map(m_d->cacheCircleInnerClip));
 
-    bool didDrawRefImage = false;
+    if (m_d->circleZoomPreviewScale > 1) {
+        QRectF sampleDocRectF = m_d->previewDocRect;
+        sampleDocRectF.setSize(sampleDocRectF.size() / m_d->circleZoomPreviewScale);
+        sampleDocRectF.moveCenter(m_d->previewDocRect.center());
 
-    paintCircleCanvasPreview(cachePainter, cacheRect, tf.map(m_d->cacheCircleInnerClip));
+        paintCircleReferenceImagePreview(cachePainter, cacheRect, sampleDocRectF, 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));
+        paintCircleCanvasPreview(cachePainter, cacheRect, sampleDocRectF, tf.map(m_d->cacheCircleInnerClip));
     }
 
     gc.drawPixmap(viewRectF.toRect(), m_d->cache);
@@ -559,21 +566,12 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
     gc.restore();
 }
 
-void KisAsyncColorSamplerHelper::paintCircleCanvasPreview(QPainter &gc, const QRectF &viewRectF, const QPainterPath &clip) {
-    QRectF sampleDocRectF = m_d->previewDocRect;
-    sampleDocRectF.setSize(sampleDocRectF.size() / m_d->circleZoomPreviewScale);
-    sampleDocRectF.moveCenter(m_d->previewDocRect.center());
-
+void KisAsyncColorSamplerHelper::paintCircleCanvasPreview(QPainter &gc, const QRectF &viewRectF, const QRectF &sampleDocRectF, const QPainterPath &clip) {
     QRectF canvasSampleRectF = m_d->canvas->image()->documentToPixel(sampleDocRectF);
 
-    dbgUI << "Preview doc rect: " << m_d->previewDocRect;
-    dbgUI << "Sample doc rect: " << sampleDocRectF;
-    dbgUI << "Canvas sample rect: " << canvasSampleRectF;
-    dbgUI << "Sample doc point: " << sampleDocRectF.center();
-
     // 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.setCompositionMode(QPainter::CompositionMode_DestinationOver);
 
     gc.setClipPath(clip);
 
@@ -585,47 +583,43 @@ void KisAsyncColorSamplerHelper::paintCircleCanvasPreview(QPainter &gc, const QR
     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
+// TODO: Fix no opacity, saturation. Broken rotation, reference image order
+void KisAsyncColorSamplerHelper::paintCircleReferenceImagePreview(QPainter &gc, const QRectF &viewRectF, const QRectF &sampleDocRectF, const QPainterPath &clip) {
     KisDocument *doc = m_d->canvas->viewManager()->document();
     if (!doc) return;
     KisReferenceImagesLayerSP refLayer = doc->referenceImagesLayer();
     if (!refLayer) return;
 
-    QRectF sampleDocRectF = m_d->previewDocRect;
-    sampleDocRectF.setSize(sampleDocRectF.size() / m_d->circleZoomPreviewScale);
-    sampleDocRectF.moveCenter(m_d->previewDocRect.center());
+    gc.setCompositionMode(QPainter::CompositionMode_SourceOver);
+    gc.setClipPath(clip);
 
-    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;
+    Q_FOREACH(KisReferenceImage *refImage, refLayer->referenceImages()) {
+        // Check if sampleRect intersect with reference image
+        QTransform refTf = refImage->absoluteTransformation();
+        QPolygonF outline = refTf.map(refImage->outlineRect());
+        if (!outline.intersects(QPolygonF(sampleDocRectF))) continue;
 
-        dbgUI << "Sampling on reference image no " << i;
+        dbgUI << "Hit test: " << refImage->hitTest(sampleDocRectF.center());
+        dbgUI << "Outline: " << outline;
+        dbgUI << "Intersected";
 
         QImage image = refImage->getImage();
-        qreal xScale = refImage->boundingRect().width() / image.width();
-        qreal yScale = refImage->boundingRect().height() / image.height();
-        QRectF refRectF = refImage->documentToShape(sampleDocRectF);
+        // TODO: Check if assuming this is correct or not
+        image.convertTo(QImage::Format_ARGB32);
 
-        dbgUI << "Shape coordinate: " << refRectF;
-        dbgUI << "Image scaling: " << refImage->transformation().m11();
+        QRectF sampleRefRectF = refImage->documentToShape(sampleDocRectF);
 
-        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);
+        qreal xScale = refImage->boundingRect().width() / image.width();
+        qreal yScale = refImage->boundingRect().height() / image.height();
+        sampleRefRectF.setTopLeft(QPointF(sampleRefRectF.topLeft().x() / xScale, sampleRefRectF.topLeft().y() / yScale));
+        sampleRefRectF.setBottomRight(QPointF(sampleRefRectF.bottomRight().x() / xScale, sampleRefRectF.bottomRight().y() / yScale));
 
-        QImage refPreview = refImage->getImage().copy(QRectF(topLeft, bottomRight).toRect());
-        refPreview.convertTo(QImage::Format_ARGB32);
+        QImage refPreview = image.copy(sampleRefRectF.toRect());
 
         gc.drawImage(viewRectF, refPreview);
     }
+
+    gc.setClipPath(QPainterPath(), Qt::NoClip);
 }
 
 void KisAsyncColorSamplerHelper::slotAddSamplingJob(const QPointF &docPoint)
diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.h b/libs/ui/tool/KisAsyncColorSamplerHelper.h
index 88d680ad581..c1cb0e4a534 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.h
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.h
@@ -81,8 +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);
+    void paintCircleCanvasPreview(QPainter &gc, const QRectF &viewRectF, const QRectF &sampleDocRectF, const QPainterPath &clip);
+    // Return true if at least one reference image preview was drawn
+    void paintCircleReferenceImagePreview(QPainter &gc, const QRectF &viewRectF, const QRectF &sampleDocRectF, 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.