[graphics/krita] libs/ui: Add configs for zoom preview, fix reference image preview when rotate

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

Add configs for zoom preview, fix reference image preview when rotate

M  +3    -5    libs/ui/KisReferenceImage.cpp
M  +25   -2    libs/ui/dialogs/kis_dlg_preferences.cc
M  +2    -0    libs/ui/dialogs/kis_dlg_preferences.h
M  +386  -358  libs/ui/forms/wdggeneralsettings.ui
M  +37   -13   libs/ui/kis_config.cc
M  +17   -3    libs/ui/kis_config.h
M  +79   -55   libs/ui/tool/KisAsyncColorSamplerHelper.cpp
M  +1    -1    libs/ui/tool/KisAsyncColorSamplerHelper.h

https://invent.kde.org/graphics/krita/-/commit/4b510407579eee2283b0fd60abb38afaff9d8611

diff --git a/libs/ui/KisReferenceImage.cpp b/libs/ui/KisReferenceImage.cpp
index ae56cec6ec6..861c1b75456 100644
--- a/libs/ui/KisReferenceImage.cpp
+++ b/libs/ui/KisReferenceImage.cpp
@@ -99,7 +99,7 @@ struct KisReferenceImage::Private : public QSharedData
 #else
         image.convertToColorSpace(QColorSpace(QColorSpace::SRgb));
 #endif
-        // It should be ok to covert to ARGB as it's saved as PNG anyways?
+        // Need to convert ref image to ARGB to draw the zoom preview when color sampling
         image.convertTo(QImage::Format_ARGB32);
 
         return (!image.isNull());
@@ -120,10 +120,8 @@ struct KisReferenceImage::Private : public QSharedData
                 gc2.drawImage(QPoint(), image);
             }
         } else {
-            // Since loading saved reference images from file skip the load...() codepath
-            // Convert here make sure
-            image.convertTo(QImage::Format_ARGB32);
-            cachedImage = image;
+            // Convert here to make sure already loaded ref images are converted
+            cachedImage = image.convertToFormat(QImage::Format_ARGB32);
         }
 
         mipmap = KisQImagePyramid(cachedImage, false);
diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc
index c6520043bbd..37c2802f9e4 100644
--- a/libs/ui/dialogs/kis_dlg_preferences.cc
+++ b/libs/ui/dialogs/kis_dlg_preferences.cc
@@ -329,10 +329,18 @@ GeneralTab::GeneralTab(QWidget *_parent, const char *_name)
 
     m_chkColorSamplerPreviewExtraCircles->setChecked(cfg.colorSamplerPreviewCircleExtraCirclesEnabled());
 
-    m_ssbColorSamplerZoomPreviewScale->setRange(100, 1000);
-    m_ssbColorSamplerZoomPreviewScale->setSingleStep(25);
+    m_grpColorSamplerZoomPreview->setChecked(cfg.colorSamplerZoomPreviewEnabled());
+
+    m_ssbColorSamplerZoomPreviewScale->setRange(100, 2000);
+    m_ssbColorSamplerZoomPreviewScale->setSingleStep(100);
     m_ssbColorSamplerZoomPreviewScale->setValue(cfg.colorSamplerZoomPreviewScale());
 
+    m_cmbColorSamplerPreviewCirclePosition->addItem(i18n("Center"));
+    m_cmbColorSamplerPreviewCirclePosition->addItem(i18n("Top"));
+    m_cmbColorSamplerPreviewCirclePosition->addItem(i18n("Top Left"));
+    m_cmbColorSamplerPreviewCirclePosition->addItem(i18n("Top Right"));
+    m_cmbColorSamplerPreviewCirclePosition->setCurrentIndex(int(cfg.colorSamplerPreviewCirclePosition()));
+
 
     KisSpinBoxI18nHelper::setText(m_ssbColorSamplerPreviewThickness, i18nc("{n} is the number value, % is the percent sign", "{n}%"));
 
@@ -792,7 +800,9 @@ void GeneralTab::setDefault()
     m_ssbColorSamplerPreviewThickness->setValue(cfg.colorSamplerPreviewCircleThickness(true));
     m_nmbColorSamplerPreviewSize->setValue(cfg.colorSamplerPreviewCircleDiameter(true));
     m_chkColorSamplerPreviewOutlineEnabled->setChecked(cfg.colorSamplerPreviewCircleOutlineEnabled(true));
+    m_grpColorSamplerZoomPreview->setChecked(cfg.colorSamplerZoomPreviewEnabled(true));
     m_ssbColorSamplerZoomPreviewScale->setValue(cfg.colorSamplerZoomPreviewScale(true));
+    m_cmbColorSamplerPreviewCirclePosition->setCurrentIndex(int(cfg.colorSamplerPreviewCirclePosition(true)));
 
 
     chkShowRootLayer->setChecked(cfg.showRootLayer(true));
@@ -981,6 +991,17 @@ qreal GeneralTab::colorSamplerZoomPreviewScale() const
     return m_ssbColorSamplerZoomPreviewScale->value();
 }
 
+bool GeneralTab::colorSamplerZoomPreviewEnabled() const
+{
+    return m_grpColorSamplerZoomPreview->isChecked();
+}
+
+KisConfig::ColorSamplerPreviewCirclePosition GeneralTab::colorSamplerPreviewCirclePosition() const
+{
+    int index = m_cmbColorSamplerPreviewCirclePosition->currentIndex();
+    return KisConfig::ColorSamplerPreviewCirclePosition(index);
+}
+
 KisConfig::SessionOnStartup GeneralTab::sessionOnStartup() const
 {
     return (KisConfig::SessionOnStartup)cmbStartupSession->currentIndex();
@@ -3071,7 +3092,9 @@ bool KisDlgPreferences::editPreferences(std::optional<PageDesc>page)
         cfg.setColorSamplerPreviewCircleThickness(m_general->colorSamplerPreviewCircleThickness());
         cfg.setColorSamplerPreviewCircleOutlineEnabled(m_general->colorSamplerPreviewCircleOutlineEnabled());
         cfg.setColorSamplerPreviewCircleExtraCirclesEnabled(m_general->colorSamplerPreviewCircleExtraCirclesEnabled());
+        cfg.setColorSamplerZoomPreviewEnabled(m_general->colorSamplerZoomPreviewEnabled());
         cfg.setColorSamplerZoomPreviewScale(m_general->colorSamplerZoomPreviewScale());
+        cfg.setColorSamplerPreviewCirclePosition(m_general->colorSamplerPreviewCirclePosition());
 
         cfg.setShowRootLayer(m_general->showRootLayer());
         cfg.setShowOutlineWhilePainting(m_general->showOutlineWhilePainting());
diff --git a/libs/ui/dialogs/kis_dlg_preferences.h b/libs/ui/dialogs/kis_dlg_preferences.h
index 6421afc9877..6ac376f7baa 100644
--- a/libs/ui/dialogs/kis_dlg_preferences.h
+++ b/libs/ui/dialogs/kis_dlg_preferences.h
@@ -74,6 +74,8 @@ public:
     bool colorSamplerPreviewCircleOutlineEnabled() const;
     bool colorSamplerPreviewCircleExtraCirclesEnabled() const;
     qreal colorSamplerZoomPreviewScale() const;
+    bool colorSamplerZoomPreviewEnabled() const;
+    KisConfig::ColorSamplerPreviewCirclePosition colorSamplerPreviewCirclePosition() const;
 
     KisConfig::SessionOnStartup sessionOnStartup() const;
     KisConfig::IconsInMenu iconsInMenu() const;
diff --git a/libs/ui/forms/wdggeneralsettings.ui b/libs/ui/forms/wdggeneralsettings.ui
index 1da5910c1e6..53e216efe89 100644
--- a/libs/ui/forms/wdggeneralsettings.ui
+++ b/libs/ui/forms/wdggeneralsettings.ui
@@ -11,7 +11,7 @@
     <x>0</x>
     <y>0</y>
     <width>1693</width>
-    <height>697</height>
+    <height>829</height>
    </rect>
   </property>
   <property name="sizePolicy">
@@ -685,375 +685,403 @@
       <attribute name="title">
        <string>Cursor</string>
       </attribute>
-      <layout class="QFormLayout" name="formLayout_9">
-       <item row="0" column="0">
-        <widget class="QLabel" name="textLabel1">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="text">
-          <string>Brush Cursor Icon:</string>
-         </property>
-         <property name="buddy">
-          <cstring>frame</cstring>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="1">
-        <widget class="QComboBox" name="m_cmbCursorShape"/>
-       </item>
-       <item row="1" column="0">
-        <widget class="QLabel" name="textLabel1_2">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="text">
-          <string>Brush Outline Shape:</string>
+      <layout class="QVBoxLayout" name="verticalLayout_9">
+       <item>
+        <widget class="QScrollArea" name="scrollArea_2">
+         <property name="widgetResizable">
+          <bool>true</bool>
          </property>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <widget class="QWidget" name="widget_2" native="true">
-         <layout class="QVBoxLayout" name="verticalLayout_8">
-          <property name="leftMargin">
-           <number>0</number>
-          </property>
-          <property name="topMargin">
-           <number>0</number>
-          </property>
-          <property name="rightMargin">
-           <number>0</number>
-          </property>
-          <property name="bottomMargin">
-           <number>0</number>
+         <widget class="QWidget" name="scrollAreaWidgetContents_2">
+          <property name="geometry">
+           <rect>
+            <x>0</x>
+            <y>0</y>
+            <width>1669</width>
+            <height>781</height>
+           </rect>
           </property>
-          <item>
-           <widget class="QComboBox" name="m_cmbOutlineShape"/>
-          </item>
-          <item>
-           <widget class="QGroupBox" name="groupBox">
-            <property name="title">
-             <string>While painting...</string>
-            </property>
-            <layout class="QVBoxLayout" name="verticalLayout_2">
-             <property name="spacing">
-              <number>3</number>
+          <layout class="QFormLayout" name="formLayout_19">
+           <item row="0" column="0">
+            <widget class="QLabel" name="textLabel1">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
              </property>
-             <property name="leftMargin">
-              <number>9</number>
+             <property name="text">
+              <string>Brush Cursor Icon:</string>
              </property>
-             <property name="topMargin">
-              <number>3</number>
+             <property name="buddy">
+              <cstring>frame</cstring>
              </property>
-             <property name="bottomMargin">
-              <number>3</number>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QComboBox" name="m_cmbCursorShape"/>
+           </item>
+           <item row="1" column="0">
+            <widget class="QLabel" name="textLabel1_2">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
              </property>
-             <item>
-              <widget class="QCheckBox" name="m_showOutlinePainting">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="minimumSize">
-                <size>
-                 <width>200</width>
-                 <height>0</height>
-                </size>
-               </property>
-               <property name="text">
-                <string>Show outline</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QCheckBox" name="m_changeBrushOutline">
-               <property name="toolTip">
-                <string>Dynamically adjust outline to match the effective size of the brush. (For example, as brush size changes due to pen pressure.)</string>
-               </property>
-               <property name="text">
-                <string>Use effective outline size</string>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </widget>
-          </item>
-         </layout>
-        </widget>
-       </item>
-       <item row="2" column="0">
-        <widget class="QLabel" name="label_11">
-         <property name="text">
-          <string>Brush Outline Color:</string>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="1">
-        <widget class="KisColorButton" name="cursorColorButton">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
-         </property>
-         <property name="text">
-          <string/>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="0" colspan="2">
-        <widget class="QGroupBox" name="m_chkSeparateEraserCursor">
-         <property name="title">
-          <string>Use separate settings for eraser</string>
-         </property>
-         <property name="checkable">
-          <bool>true</bool>
-         </property>
-         <property name="checked">
-          <bool>false</bool>
-         </property>
-         <layout class="QFormLayout" name="formLayout_14">
-          <item row="0" column="1">
-           <widget class="QComboBox" name="m_cmbEraserCursorShape"/>
-          </item>
-          <item row="0" column="0">
-           <widget class="QLabel" name="label_19">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="text">
-             <string>Eraser Cursor Icon:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="1" column="0">
-           <widget class="QLabel" name="label_20">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="text">
-             <string>Eraser Outline Shape:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="1" column="1">
-           <widget class="QWidget" name="widget_7" native="true">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <layout class="QVBoxLayout" name="verticalLayout_10">
-             <property name="leftMargin">
-              <number>0</number>
+             <property name="text">
+              <string>Brush Outline Shape:</string>
              </property>
-             <property name="topMargin">
-              <number>0</number>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QWidget" name="widget_2" native="true">
+             <layout class="QVBoxLayout" name="verticalLayout_8">
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="topMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="bottomMargin">
+               <number>0</number>
+              </property>
+              <item>
+               <widget class="QComboBox" name="m_cmbOutlineShape"/>
+              </item>
+              <item>
+               <widget class="QGroupBox" name="groupBox">
+                <property name="title">
+                 <string>While painting...</string>
+                </property>
+                <layout class="QVBoxLayout" name="verticalLayout_2">
+                 <property name="spacing">
+                  <number>3</number>
+                 </property>
+                 <property name="leftMargin">
+                  <number>9</number>
+                 </property>
+                 <property name="topMargin">
+                  <number>3</number>
+                 </property>
+                 <property name="bottomMargin">
+                  <number>3</number>
+                 </property>
+                 <item>
+                  <widget class="QCheckBox" name="m_showOutlinePainting">
+                   <property name="sizePolicy">
+                    <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                     <horstretch>0</horstretch>
+                     <verstretch>0</verstretch>
+                    </sizepolicy>
+                   </property>
+                   <property name="minimumSize">
+                    <size>
+                     <width>200</width>
+                     <height>0</height>
+                    </size>
+                   </property>
+                   <property name="text">
+                    <string>Show outline</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item>
+                  <widget class="QCheckBox" name="m_changeBrushOutline">
+                   <property name="toolTip">
+                    <string>Dynamically adjust outline to match the effective size of the brush. (For example, as brush size changes due to pen pressure.)</string>
+                   </property>
+                   <property name="text">
+                    <string>Use effective outline size</string>
+                   </property>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item row="2" column="0">
+            <widget class="QLabel" name="label_11">
+             <property name="text">
+              <string>Brush Outline Color:</string>
              </property>
-             <property name="rightMargin">
-              <number>0</number>
+            </widget>
+           </item>
+           <item row="2" column="1">
+            <widget class="KisColorButton" name="cursorColorButton">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
              </property>
-             <property name="bottomMargin">
-              <number>0</number>
+             <property name="text">
+              <string/>
              </property>
-             <item>
-              <widget class="QComboBox" name="m_cmbEraserOutlineShape"/>
-             </item>
-             <item>
-              <widget class="QGroupBox" name="groupBox_6">
-               <property name="sizePolicy">
-                <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                 <horstretch>0</horstretch>
-                 <verstretch>0</verstretch>
-                </sizepolicy>
-               </property>
-               <property name="title">
-                <string>While painting with an eraser...</string>
-               </property>
-               <layout class="QVBoxLayout" name="verticalLayout_5">
-                <property name="spacing">
-                 <number>3</number>
+            </widget>
+           </item>
+           <item row="3" column="0" colspan="2">
+            <widget class="QGroupBox" name="m_chkSeparateEraserCursor">
+             <property name="title">
+              <string>Use separate settings for eraser</string>
+             </property>
+             <property name="checkable">
+              <bool>true</bool>
+             </property>
+             <property name="checked">
+              <bool>false</bool>
+             </property>
+             <layout class="QFormLayout" name="formLayout_14">
+              <item row="0" column="1">
+               <widget class="QComboBox" name="m_cmbEraserCursorShape"/>
+              </item>
+              <item row="0" column="0">
+               <widget class="QLabel" name="label_19">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
                 </property>
-                <property name="topMargin">
-                 <number>3</number>
+                <property name="text">
+                 <string>Eraser Cursor Icon:</string>
                 </property>
-                <property name="bottomMargin">
-                 <number>3</number>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QLabel" name="label_20">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
                 </property>
-                <item>
-                 <widget class="QCheckBox" name="m_showEraserOutlinePainting">
-                  <property name="text">
-                   <string>Show outline</string>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QCheckBox" name="m_changeEraserBrushOutline">
-                  <property name="toolTip">
-                   <string>Dynamically adjust outline to match the effective size of the brush. (For example, as brush size changes due to pen pressure.)</string>
-                  </property>
-                  <property name="text">
-                   <string>Use effective outline size</string>
-                  </property>
-                 </widget>
-                </item>
-               </layout>
-              </widget>
-             </item>
-            </layout>
-           </widget>
-          </item>
-          <item row="2" column="0">
-           <widget class="QLabel" name="label_21">
-            <property name="text">
-             <string>Eraser Outline Color:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="2" column="1">
-           <widget class="KisColorButton" name="eraserCursorColorButton">
-            <property name="maximumSize">
-             <size>
-              <width>48</width>
-              <height>25</height>
-             </size>
-            </property>
-            <property name="text">
-             <string/>
-            </property>
-           </widget>
-          </item>
-         </layout>
-        </widget>
-       </item>
-       <item row="4" column="0">
-        <widget class="QLabel" name="m_lblColorSamplerPreviewStyle">
-         <property name="text">
-          <string>Color Sampler Shape:</string>
-         </property>
-        </widget>
-       </item>
-       <item row="4" column="1">
-        <widget class="QComboBox" name="m_cmbColorSamplerPreviewStyle"/>
-       </item>
-       <item row="6" column="0">
-        <widget class="QLabel" name="m_lblColorSamplerPreviewSizePreviewEmpty">
-         <property name="text">
-          <string/>
-         </property>
-        </widget>
-       </item>
-       <item row="11" column="0" colspan="2">
-        <spacer name="verticalSpacer_3">
-         <property name="orientation">
-          <enum>Qt::Vertical</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>20</width>
-           <height>40</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item row="5" column="0" colspan="2">
-        <widget class="QFrame" name="m_frmColorSamplerCircleSettings">
-         <property name="frameShape">
-          <enum>QFrame::StyledPanel</enum>
-         </property>
-         <property name="frameShadow">
-          <enum>QFrame::Raised</enum>
-         </property>
-         <layout class="QFormLayout" name="m_frmColorSamplerCircleSettingsLayout">
-          <item row="1" column="0">
-           <widget class="QLabel" name="m_lblColorSamplerPreviewSize">
-            <property name="text">
-             <string>Diameter:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="1" column="1">
-           <widget class="KisSliderSpinBox" name="m_nmbColorSamplerPreviewSize"/>
-          </item>
-          <item row="0" column="0" colspan="2">
-           <widget class="KisColorSamplerPreviewPreview" name="m_lblColorSamplerPreviewSizePreview">
-            <property name="sizePolicy">
-             <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-              <horstretch>0</horstretch>
-              <verstretch>0</verstretch>
-             </sizepolicy>
-            </property>
-            <property name="minimumSize">
-             <size>
-              <width>0</width>
-              <height>20</height>
-             </size>
-            </property>
-           </widget>
-          </item>
-          <item row="2" column="0">
-           <widget class="QLabel" name="m_lblColorSamplerPreviewThickness">
-            <property name="text">
-             <string>Thickness:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="2" column="1">
-           <widget class="KisDoubleSliderSpinBox" name="m_ssbColorSamplerPreviewThickness"/>
-          </item>
-          <item row="4" column="1">
-           <widget class="QCheckBox" name="m_chkColorSamplerPreviewOutlineEnabled">
-            <property name="text">
-             <string>Enable Outline</string>
-            </property>
-           </widget>
-          </item>
-          <item row="5" column="1">
-           <widget class="QCheckBox" name="m_chkColorSamplerPreviewExtraCircles">
-            <property name="text">
-             <string>Extra Comparison Space</string>
-            </property>
-           </widget>
-          </item>
-          <item row="3" column="1">
-           <widget class="KisSliderSpinBox" name="m_ssbColorSamplerZoomPreviewScale">
-            <property name="suffix">
-             <string>%</string>
-            </property>
-            <property name="minimum">
-             <number>100</number>
-            </property>
-            <property name="maximum">
-             <number>1000</number>
-            </property>
-            <property name="singleStep">
-             <number>25</number>
-            </property>
-           </widget>
-          </item>
-          <item row="3" column="0">
-           <widget class="QLabel" name="m_lblColorSamplerZoomPreviewScale">
-            <property name="text">
-             <string>Zoom Preview Scale:</string>
-            </property>
-           </widget>
-          </item>
-         </layout>
+                <property name="text">
+                 <string>Eraser Outline Shape:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="1">
+               <widget class="QWidget" name="widget_7" native="true">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <layout class="QVBoxLayout" name="verticalLayout_10">
+                 <property name="leftMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="topMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="rightMargin">
+                  <number>0</number>
+                 </property>
+                 <property name="bottomMargin">
+                  <number>0</number>
+                 </property>
+                 <item>
+                  <widget class="QComboBox" name="m_cmbEraserOutlineShape"/>
+                 </item>
+                 <item>
+                  <widget class="QGroupBox" name="groupBox_6">
+                   <property name="sizePolicy">
+                    <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                     <horstretch>0</horstretch>
+                     <verstretch>0</verstretch>
+                    </sizepolicy>
+                   </property>
+                   <property name="title">
+                    <string>While painting with an eraser...</string>
+                   </property>
+                   <layout class="QVBoxLayout" name="verticalLayout_5">
+                    <property name="spacing">
+                     <number>3</number>
+                    </property>
+                    <property name="topMargin">
+                     <number>3</number>
+                    </property>
+                    <property name="bottomMargin">
+                     <number>3</number>
+                    </property>
+                    <item>
+                     <widget class="QCheckBox" name="m_showEraserOutlinePainting">
+                      <property name="text">
+                       <string>Show outline</string>
+                      </property>
+                     </widget>
+                    </item>
+                    <item>
+                     <widget class="QCheckBox" name="m_changeEraserBrushOutline">
+                      <property name="toolTip">
+                       <string>Dynamically adjust outline to match the effective size of the brush. (For example, as brush size changes due to pen pressure.)</string>
+                      </property>
+                      <property name="text">
+                       <string>Use effective outline size</string>
+                      </property>
+                     </widget>
+                    </item>
+                   </layout>
+                  </widget>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+              <item row="2" column="0">
+               <widget class="QLabel" name="label_21">
+                <property name="text">
+                 <string>Eraser Outline Color:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="1">
+               <widget class="KisColorButton" name="eraserCursorColorButton">
+                <property name="maximumSize">
+                 <size>
+                  <width>48</width>
+                  <height>25</height>
+                 </size>
+                </property>
+                <property name="text">
+                 <string/>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item row="4" column="0">
+            <widget class="QLabel" name="m_lblColorSamplerPreviewStyle">
+             <property name="text">
+              <string>Color Sampler Shape:</string>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="1">
+            <widget class="QComboBox" name="m_cmbColorSamplerPreviewStyle"/>
+           </item>
+           <item row="5" column="0" colspan="2">
+            <widget class="QFrame" name="m_frmColorSamplerCircleSettings">
+             <property name="frameShape">
+              <enum>QFrame::Shape::StyledPanel</enum>
+             </property>
+             <property name="frameShadow">
+              <enum>QFrame::Shadow::Raised</enum>
+             </property>
+             <layout class="QFormLayout" name="m_frmColorSamplerCircleSettingsLayout">
+              <item row="0" column="0" colspan="2">
+               <widget class="KisColorSamplerPreviewPreview" name="m_lblColorSamplerPreviewSizePreview">
+                <property name="sizePolicy">
+                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+                  <horstretch>0</horstretch>
+                  <verstretch>0</verstretch>
+                 </sizepolicy>
+                </property>
+                <property name="minimumSize">
+                 <size>
+                  <width>0</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <widget class="QLabel" name="m_lblColorSamplerPreviewSize">
+                <property name="text">
+                 <string>Diameter:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="1">
+               <widget class="KisSliderSpinBox" name="m_nmbColorSamplerPreviewSize"/>
+              </item>
+              <item row="2" column="0">
+               <widget class="QLabel" name="m_lblColorSamplerPreviewThickness">
+                <property name="text">
+                 <string>Thickness:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="1">
+               <widget class="KisDoubleSliderSpinBox" name="m_ssbColorSamplerPreviewThickness"/>
+              </item>
+              <item row="3" column="1">
+               <widget class="QCheckBox" name="m_chkColorSamplerPreviewOutlineEnabled">
+                <property name="text">
+                 <string>Enable Outline</string>
+                </property>
+               </widget>
+              </item>
+              <item row="4" column="1">
+               <widget class="QCheckBox" name="m_chkColorSamplerPreviewExtraCircles">
+                <property name="text">
+                 <string>Extra Comparison Space</string>
+                </property>
+               </widget>
+              </item>
+              <item row="5" column="0" colspan="2">
+               <widget class="QGroupBox" name="m_grpColorSamplerZoomPreview">
+                <property name="title">
+                 <string>Enable Zoom Preview (Pixel-Perfect Color Picker)</string>
+                </property>
+                <property name="checkable">
+                 <bool>true</bool>
+                </property>
+                <layout class="QFormLayout" name="formLayout_3">
+                 <item row="0" column="0">
+                  <widget class="QLabel" name="m_lblColorSamplerZoomPreviewScale">
+                   <property name="text">
+                    <string>Zoom Preview Scale:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="1">
+                  <widget class="KisSliderSpinBox" name="m_ssbColorSamplerZoomPreviewScale">
+                   <property name="suffix">
+                    <string>%</string>
+                   </property>
+                   <property name="minimum">
+                    <number>100</number>
+                   </property>
+                   <property name="maximum">
+                    <number>1000</number>
+                   </property>
+                   <property name="singleStep">
+                    <number>25</number>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="0">
+                  <widget class="QLabel" name="m_lblColorSamplerPreviewCirclePosition">
+                   <property name="text">
+                    <string>Color Sampler Position:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QComboBox" name="m_cmbColorSamplerPreviewCirclePosition"/>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+             </layout>
+            </widget>
+           </item>
+           <item row="6" column="0">
+            <widget class="QLabel" name="m_lblColorSamplerPreviewSizePreviewEmpty">
+             <property name="text">
+              <string/>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
         </widget>
        </item>
       </layout>
@@ -1365,7 +1393,7 @@
             <x>0</x>
             <y>0</y>
             <width>1689</width>
-            <height>669</height>
+            <height>801</height>
            </rect>
           </property>
           <property name="sizePolicy">
diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc
index 6afecc2f9e6..2e36a0c4943 100644
--- a/libs/ui/kis_config.cc
+++ b/libs/ui/kis_config.cc
@@ -569,19 +569,6 @@ void KisConfig::setColorSamplerPreviewCircleThickness(qreal thickness)
     m_cfg.writeEntry("colorSamplerPreviewCircleThickness", thickness);
 }
 
-
-qreal KisConfig::colorSamplerZoomPreviewScale(bool defaultValue) const {
-    qreal def = 500;
-    if (!defaultValue) {
-        return m_cfg.readEntry("colorSamplerZoomPreviewScale", def);
-    }
-    return def;
-}
-
-void KisConfig::setColorSamplerZoomPreviewScale(qreal scale) {
-    m_cfg.writeEntry("colorSamplerZoomPreviewScale", scale);
-}
-
 bool KisConfig::colorSamplerPreviewCircleOutlineEnabled(bool defaultValue) const
 {
     bool def = true;
@@ -610,6 +597,43 @@ void KisConfig::setColorSamplerPreviewCircleExtraCirclesEnabled(bool enabled)
     m_cfg.writeEntry("colorSamplerPreviewCircleExtraCirclesEnabled", enabled);
 }
 
+bool KisConfig::colorSamplerZoomPreviewEnabled(bool defaultValue) const {
+    bool def = true;
+    if (!defaultValue) {
+        return m_cfg.readEntry("colorSamplerZoomPreviewEnabled", def);
+    }
+    return def;
+}
+void KisConfig::setColorSamplerZoomPreviewEnabled(bool enabled) {
+    m_cfg.writeEntry("colorSamplerZoomPreviewEnabled", enabled);
+}
+
+qreal KisConfig::colorSamplerZoomPreviewScale(bool defaultValue) const {
+    qreal def = 500;
+    if (!defaultValue) {
+        return m_cfg.readEntry("colorSamplerZoomPreviewScale", def);
+    }
+    return def;
+}
+
+void KisConfig::setColorSamplerZoomPreviewScale(qreal scale) {
+    m_cfg.writeEntry("colorSamplerZoomPreviewScale", scale);
+}
+
+KisConfig::ColorSamplerPreviewCirclePosition KisConfig::colorSamplerPreviewCirclePosition(bool defaultValue) const {
+    if (!defaultValue) {
+        int pos = m_cfg.readEntry("colorSamplerPreviewCirclePosition", int(ColorSamplerPreviewCirclePosition::Center));
+        if (pos >= 0 && pos < int(ColorSamplerPreviewCirclePosition::Count)) {
+            return ColorSamplerPreviewCirclePosition(pos);
+        }
+    }
+    return ColorSamplerPreviewCirclePosition::Center;
+}
+
+void KisConfig::setColorSamplerPreviewCirclePosition(KisConfig::ColorSamplerPreviewCirclePosition position) {
+    m_cfg.writeEntry("colorSamplerPreviewCirclePosition", int(position));
+}
+
 bool KisConfig::useDirtyPresets(bool defaultValue) const
 {
    return (defaultValue ? false : m_cfg.readEntry("useDirtyPresets", true));
diff --git a/libs/ui/kis_config.h b/libs/ui/kis_config.h
index 323bba25eab..88f6cb23abe 100644
--- a/libs/ui/kis_config.h
+++ b/libs/ui/kis_config.h
@@ -153,15 +153,29 @@ public:
     qreal colorSamplerPreviewCircleThickness(bool defaultValue = false) const;
     void setColorSamplerPreviewCircleThickness(qreal thickness);
 
-    qreal colorSamplerZoomPreviewScale(bool defaultValue = false) const;
-    void setColorSamplerZoomPreviewScale(qreal scale);
-
     bool colorSamplerPreviewCircleOutlineEnabled(bool defaultValue = false) const;
     void setColorSamplerPreviewCircleOutlineEnabled(bool enabled);
 
     bool colorSamplerPreviewCircleExtraCirclesEnabled(bool defaultValue = false) const;
     void setColorSamplerPreviewCircleExtraCirclesEnabled(bool enabled);
 
+    bool colorSamplerZoomPreviewEnabled(bool defaultValue = false) const;
+    void setColorSamplerZoomPreviewEnabled(bool enabled);
+
+    qreal colorSamplerZoomPreviewScale(bool defaultValue = false) const;
+    void setColorSamplerZoomPreviewScale(qreal scale);
+
+    enum class ColorSamplerPreviewCirclePosition {
+        Center,
+        Top,
+        TopLeft,
+        TopRight,
+        Count,
+    };
+
+    ColorSamplerPreviewCirclePosition colorSamplerPreviewCirclePosition(bool defaultValue = false) const;
+    void setColorSamplerPreviewCirclePosition(ColorSamplerPreviewCirclePosition position);
+
     /**
      * Controls if the canvas should have a separate color managed surface.
      * Even though the surface can be created on any platform the proper
diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
index 0d89528f1e6..d9d58e52314 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
@@ -74,8 +74,8 @@ struct KisAsyncColorSamplerHelper::Private
     bool circleZoomPreviewEnabled {true};
     qreal circleZoomPreviewScale {5};
     int circleZoomPreviewCrosshairSize {10};
-    int circlePreviewHorizontalOffset {0};
-    int circlePreviewVerticalOffset {-100};
+    KisConfig::ColorSamplerPreviewCirclePosition circlePreviewPosition = KisConfig::ColorSamplerPreviewCirclePosition::Center;
+    QPointF sampleDocPoint;
 
     QPainterPath cacheCircleInnerClip;
     QVector<KisReferenceImage*> cacheReferenceImageList; // Sorted reference images by zIndex
@@ -150,7 +150,45 @@ struct KisAsyncColorSamplerHelper::Private
 
     QRectF colorPreviewRectForCircle()
     {
-        return QRectF(-circlePreviewDiameter / 2.0, -circlePreviewDiameter / 2.0, circlePreviewDiameter, circlePreviewDiameter);
+        QRectF circleRect = QRectF(-circlePreviewDiameter / 2.0, -circlePreviewDiameter / 2.0, circlePreviewDiameter, circlePreviewDiameter);
+
+        // If zoom preview enabled, it's possible to offset the color sampler preview and still be accurate
+        // This can help when sampling color using finger gesture
+        if (circleZoomPreviewEnabled) {
+            if (circlePreviewPosition == KisConfig::ColorSamplerPreviewCirclePosition::Center) return circleRect;
+
+            constexpr qreal OFFSET = 10.0;
+            constexpr qreal OFFSET_ABOVE = 20.0;
+            bool mirrored = canvas->xAxisMirrored();
+            bool flipped = canvas->yAxisMirrored();
+            KisConfig::ColorSamplerPreviewCirclePosition effectivePos;
+            if (mirrored && circlePreviewPosition == KisConfig::ColorSamplerPreviewCirclePosition::TopLeft) {
+                effectivePos = KisConfig::ColorSamplerPreviewCirclePosition::TopRight;
+            }
+            else if (mirrored && circlePreviewPosition == KisConfig::ColorSamplerPreviewCirclePosition::TopRight) {
+                effectivePos = KisConfig::ColorSamplerPreviewCirclePosition::TopLeft;
+            }
+            else effectivePos = circlePreviewPosition;
+
+            qreal x = 0;
+            qreal y = flipped ? circlePreviewDiameter / 2.0 + OFFSET_ABOVE : -circlePreviewDiameter / 2.0 - OFFSET_ABOVE;
+
+            switch (effectivePos) {
+            case KisConfig::ColorSamplerPreviewCirclePosition::TopLeft:
+                x = -circlePreviewDiameter / 2.0 - OFFSET;
+                break;
+            case KisConfig::ColorSamplerPreviewCirclePosition::TopRight:
+                x = circlePreviewDiameter / 2.0 + OFFSET;
+                break;
+            default:
+                x = 0;
+                break;
+            }
+
+            return circleRect.translated(QPointF(x, y));
+        }
+
+        return circleRect;
     }
 
     QRectF colorPreviewDocRect(const QPointF &outlineDocPoint)
@@ -177,12 +215,6 @@ struct KisAsyncColorSamplerHelper::Private
             break;
         }
 
-        // If zoom preview enabled, it's possible to offset the color sampler preview and still be accurate
-        // This can help when sampling color using finger gesture
-        if (circleZoomPreviewEnabled) {
-            colorPreviewViewRect.translate(QPointF(circlePreviewHorizontalOffset, circlePreviewVerticalOffset));
-        }
-
         const QRectF colorPreviewDocumentRect = converter().viewToDocument(colorPreviewViewRect);
         return colorPreviewDocumentRect.translated(outlineDocPoint);
     }
@@ -201,6 +233,24 @@ struct KisAsyncColorSamplerHelper::Private
             return a->zIndex() < b->zIndex();
         });
     }
+
+    QRect standardizeZoomPreviewPixelRect(QRect pixelRect) {
+        // If width and height get rounded to different number, the center will be stuck between pixel border
+        if (pixelRect.width() != pixelRect.height()) {
+            if (pixelRect.width() % 2 == 0) pixelRect.setWidth(pixelRect.height());
+            else pixelRect.setHeight(pixelRect.width());
+        }
+        // If width and height is even, the center will be stuck in pixel corner
+        else if (pixelRect.width() % 2 == 0) {
+            pixelRect.setWidth(pixelRect.width() - 1);
+            pixelRect.setHeight(pixelRect.height() - 1);
+        }
+
+        // Minimum sample size should be 3 to be meaningful
+        if (pixelRect.width() <= 2 || pixelRect.height() <= 2) pixelRect.setSize(QSize(3, 3));
+
+        return pixelRect;
+    }
 };
 
 KisAsyncColorSamplerHelper::KisAsyncColorSamplerHelper(KisCanvas2 *canvas)
@@ -251,7 +301,9 @@ void KisAsyncColorSamplerHelper::activate(bool sampleCurrentLayer, bool pickFgCo
     m_d->circlePreviewThickness = cfg.colorSamplerPreviewCircleThickness()/100.0; // saved in percentages
     m_d->circlePreviewOutlineEnabled = cfg.colorSamplerPreviewCircleOutlineEnabled();
     m_d->circlePreviewExtraCircles = cfg.colorSamplerPreviewCircleExtraCirclesEnabled();
+    m_d->circleZoomPreviewEnabled = cfg.colorSamplerZoomPreviewEnabled();
     m_d->circleZoomPreviewScale = cfg.colorSamplerZoomPreviewScale()/100.0; // saved in percentages
+    m_d->circlePreviewPosition = cfg.colorSamplerPreviewCirclePosition();
 
     // Update and sort the list of current reference images currently on canvas
     m_d->updateCachedReferenceImages();
@@ -385,6 +437,8 @@ QRectF KisAsyncColorSamplerHelper::colorPreviewDocRect(const QPointF &docPoint)
 {
     if (!m_d->showPreview) return QRectF();
 
+    m_d->sampleDocPoint = docPoint;
+
     KisConfig cfg(true);
     m_d->style = cfg.colorSamplerPreviewStyle();
     m_d->previewDocRect = m_d->colorPreviewDocRect(docPoint);
@@ -601,13 +655,7 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
 
         // Sample a rect with size that is (zoomPreviewScale) times smaller than (previewDocRect size)
         sampleDocRectF.setSize(sampleDocRectF.size() / m_d->circleZoomPreviewScale);
-        sampleDocRectF.moveCenter(m_d->previewDocRect.center());
-        dbgUI << "Preview rect:" << m_d->previewDocRect;
-        dbgUI << "Sample rect:" << sampleDocRectF;
-
-        // Invert the preview offset to move the sample rect to the actual position sampled
-        QPointF invertOffsetDocPoint = m_d->canvas->coordinatesConverter()->viewToDocument(QPointF(-m_d->circlePreviewHorizontalOffset, -m_d->circlePreviewVerticalOffset));
-        sampleDocRectF.translate(invertOffsetDocPoint);
+        sampleDocRectF.moveCenter(m_d->sampleDocPoint);
 
         paintCircleCanvasPreview(cachePainter, cacheRect, sampleDocRectF, tf.map(m_d->cacheCircleInnerClip));
 
@@ -615,7 +663,7 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
 
 
         // Draw crosshair if preview is offseted
-        if (m_d->circlePreviewHorizontalOffset != 0 || m_d->circlePreviewVerticalOffset != 0) {
+        if (m_d->circlePreviewPosition != KisConfig::ColorSamplerPreviewCirclePosition::Center) {
             QColor crosshairColor = Qt::black;
             // Apparently this fomular is outdated and inaccurate. But the accurate version require calculating power, probably overkill anyway
             qreal luminance = (0.299 * currentColor.redF() + 0.587 * currentColor.greenF() + 0.114 * currentColor.blueF());
@@ -635,9 +683,6 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
     gc.restore();
 }
 
-// Return a cached QImage of canvas.
-// The returned QImage is the whole cached area (because it wouldn't make sense to copy the requested area from the cached QImage only to draw it later?)
-// The cached area max size is the canvas size
 QImage KisAsyncColorSamplerHelper::cacheCanvasImage(QRect &canvasPixelRect) {
     KisImageWSP canvasImage = m_d->canvas->image();
 
@@ -652,9 +697,12 @@ 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
+        // Cache an area larger than the needed preview area to avoid rapid small dynamic allocations
+        // Attempt to reduce cache size when sample size is big to reduce delay
         qreal cacheScale = 4;
+        if (canvasPixelRect.width() > 1000) cacheScale = 2;
+        else if (canvasPixelRect.width() > 2000) cacheScale = 1;
+
         QRect cacheCanvasRect = canvasPixelRect;
         cacheCanvasRect.setSize(canvasPixelRect.size() * cacheScale);
         cacheCanvasRect.moveCenter(canvasPixelRect.center());
@@ -682,22 +730,9 @@ void KisAsyncColorSamplerHelper::paintCircleCanvasPreview(QPainter &gc, const QR
     gc.save();
 
     KisImageWSP image = m_d->canvas->image();
-    QRect canvasPixelRect = image->documentToPixel(sampleDocRectF).toRect();
-
-    // If width and height get rounded to different number, the center will be stuck between pixel border
-    if (canvasPixelRect.width() != canvasPixelRect.height()) {
-        if (canvasPixelRect.width() % 2 == 0) canvasPixelRect.setWidth(canvasPixelRect.height());
-        else canvasPixelRect.setHeight(canvasPixelRect.width());
-    }
-    // If width and height is even, the center will be stuck in pixel corner
-    else if (canvasPixelRect.width() % 2 == 0) {
-        canvasPixelRect.setWidth(canvasPixelRect.width() - 1);
-        canvasPixelRect.setHeight(canvasPixelRect.height() - 1);
-    }
 
-    dbgUI << "Pixel rect:" << canvasPixelRect;
-    // In case zoom and scale is both so large that sample size becomes 0
-    if (canvasPixelRect.width() == 0 || canvasPixelRect.height() == 0) canvasPixelRect.setSize(QSize(1, 1));
+    QRect canvasPixelRect = image->documentToPixel(sampleDocRectF).toRect();
+    canvasPixelRect = m_d->standardizeZoomPreviewPixelRect(canvasPixelRect);
 
     // Make sure the center is the pixel currently sampled (in case of rounding errors)
     canvasPixelRect.moveCenter(image->documentToImagePixelFloored(sampleDocRectF.center()));
@@ -731,29 +766,18 @@ void KisAsyncColorSamplerHelper::paintCircleReferenceImagePreview(QPainter &gc,
         gc.save();
 
         QImage image = refImage->getCachedImage();
-        // image.convertTo(QImage::Format_ARGB32); Do this in KisReferenceImage to avoid having to copy?
 
-        QPoint sampleRefPoint = refImage->documentToPixelFloored(sampleDocRectF.center());
+        QPoint refPixelPoint = refImage->documentToPixelFloored(sampleDocRectF.center());
 
+        // Avoid using KisReferenceImage::documentToPixel because it use absoluteTransformation.invert()
+        // Which will take rotation into account and cause some quirks
         qreal xScale = refImage->boundingRect().width() / image.width();
         qreal yScale = refImage->boundingRect().height() / image.height();
 
-        QRect sampleRefRect = QRect(sampleRefPoint, QSize(sampleDocRectF.width() / xScale, sampleDocRectF.height() / yScale));
-
-        // If width and height get rounded to different number, the center will be stuck between pixel border
-        if (sampleRefRect.width() != sampleRefRect.height()) {
-            if (sampleRefRect.width() % 2 == 0) sampleRefRect.setWidth(sampleRefRect.height());
-            else sampleRefRect.setHeight(sampleRefRect.width());
-        }
-        // If width and height is even, the center will be stuck in pixel corner
-        else if (sampleRefRect.width() % 2 == 0) {
-            sampleRefRect.setWidth(sampleRefRect.width() - 1);
-            sampleRefRect.setHeight(sampleRefRect.height() - 1);
-        }
-
-        if (sampleRefRect.width() == 0 || sampleRefRect.height() == 0) sampleRefRect.setSize(QSize(1, 1));
+        QRect refPixelRect = QRect(refPixelPoint, QSize(sampleDocRectF.width() / xScale, sampleDocRectF.height() / yScale));
+        refPixelRect = m_d->standardizeZoomPreviewPixelRect(refPixelRect);
 
-        sampleRefRect.moveCenter(sampleRefPoint);
+        refPixelRect.moveCenter(refPixelPoint);
 
         // Rotate the painter, draw, rotate back is seemingly easier than
         // trying to rotate the image and the shenanighens that follow
@@ -761,7 +785,7 @@ void KisAsyncColorSamplerHelper::paintCircleReferenceImagePreview(QPainter &gc,
         gc.rotate(refImage->rotation());
         gc.translate(-viewRectF.center());
 
-        gc.drawImage(viewRectF, image, sampleRefRect);
+        gc.drawImage(viewRectF, image, refPixelRect);
 
         gc.restore();
     }
diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.h b/libs/ui/tool/KisAsyncColorSamplerHelper.h
index 25bb6266239..7f97427fcb4 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.h
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.h
@@ -85,7 +85,7 @@ private:
     // Return true if at least one reference image preview was drawn
     void paintCircleReferenceImagePreview(QPainter &gc, const QRectF &viewRectF, const QRectF &sampleDocRectF, const QPainterPath &clip);
 
-    // Returns a cached canvas image that should either contain the canvasPixelRectF, or the whole canvas if canvasPixelRectF > canvas size.
+    // Returns a QImage that should either contain the canvasPixelRectF, or the whole canvas if canvasPixelRectF > canvas size.
     // Also modify the input rect to point to the same position relative to the returned image
     QImage cacheCanvasImage(QRect &canvasPixelRect);
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.