[krita/krita/4.0] libs/image/layerstyles: Connect Erode/Dilate algorithms to "Stroke" layer style

Dmitry Kazakov null at kde.org
Sat Jun 9 14:12:58 UTC 2018


Git commit ace6d8252a5a7b783ace53added6584f315ebe1f by Dmitry Kazakov.
Committed on 09/06/2018 at 09:00.
Pushed by dkazakov into branch 'krita/4.0'.

Connect Erode/Dilate algorithms to "Stroke" layer style

Now it is **much** faster, more roundish and doesn't eat your memory :)

BUG:361130
BUG:390985
CC:kimageshop at kde.org

M  +0    -18   libs/image/layerstyles/kis_layer_style_filter_environment.cpp
M  +0    -2    libs/image/layerstyles/kis_layer_style_filter_environment.h
M  +43   -46   libs/image/layerstyles/kis_ls_stroke_filter.cpp

https://commits.kde.org/krita/ace6d8252a5a7b783ace53added6584f315ebe1f

diff --git a/libs/image/layerstyles/kis_layer_style_filter_environment.cpp b/libs/image/layerstyles/kis_layer_style_filter_environment.cpp
index 4ba2d485974..f1e7438a568 100644
--- a/libs/image/layerstyles/kis_layer_style_filter_environment.cpp
+++ b/libs/image/layerstyles/kis_layer_style_filter_environment.cpp
@@ -105,24 +105,6 @@ int KisLayerStyleFilterEnvironment::currentLevelOfDetail() const
         m_d->sourceLayer->original()->defaultBounds()->currentLevelOfDetail() : 0;
 }
 
-QPainterPath KisLayerStyleFilterEnvironment::layerOutlineCache() const
-{
-    // TODO: make it really cachable!
-    Q_ASSERT(m_d->sourceLayer);
-    KisPaintDeviceSP srcDevice = m_d->sourceLayer->projection();
-    QRect srcRect = srcDevice->exactBounds();
-    if (srcRect.isEmpty()) return QPainterPath();
-
-    KisSelectionSP baseSelection =
-        KisLsUtils::selectionFromAlphaChannel(srcDevice, srcRect);
-    KisPixelSelectionSP selection = baseSelection->pixelSelection();
-
-    // needs no 'invalidate' call
-    selection->recalculateOutlineCache();
-
-    return selection->outlineCache();
-}
-
 void KisLayerStyleFilterEnvironment::setupFinalPainter(KisPainter *gc,
                                                        quint8 opacity,
                                                        const QBitArray &channelFlags) const
diff --git a/libs/image/layerstyles/kis_layer_style_filter_environment.h b/libs/image/layerstyles/kis_layer_style_filter_environment.h
index 940f1ecdb8f..a54c9475c64 100644
--- a/libs/image/layerstyles/kis_layer_style_filter_environment.h
+++ b/libs/image/layerstyles/kis_layer_style_filter_environment.h
@@ -41,8 +41,6 @@ public:
     QRect defaultBounds() const;
     int currentLevelOfDetail() const;
 
-    QPainterPath layerOutlineCache() const;
-
     void setupFinalPainter(KisPainter *gc,
                            quint8 opacity,
                            const QBitArray &channelFlags) const;
diff --git a/libs/image/layerstyles/kis_ls_stroke_filter.cpp b/libs/image/layerstyles/kis_ls_stroke_filter.cpp
index 2843abfc64e..d152f1edc57 100644
--- a/libs/image/layerstyles/kis_ls_stroke_filter.cpp
+++ b/libs/image/layerstyles/kis_ls_stroke_filter.cpp
@@ -44,22 +44,33 @@
 #include "kis_ls_utils.h"
 #include "kis_multiple_projection.h"
 
+namespace {
 
-KisLsStrokeFilter::KisLsStrokeFilter()
-    : KisLayerStyleFilter(KoID("lsstroke", i18n("Stroke (style)")))
+int borderSize(psd_stroke_position position, int size)
 {
+    int border = 0;
+
+    switch (position) {
+    case psd_stroke_outside:
+        border = 2 * size + 1;
+        break;
+    case psd_stroke_center:
+        border = size + 1;
+        break;
+    case psd_stroke_inside:
+        border = 1;
+        break;
+    }
+
+    return border;
+}
+
 }
 
-void paintPathOnSelection(KisPixelSelectionSP selection,
-                          const QPainterPath &path,
-                          const QRect &applyRect,
-                          int size)
+
+KisLsStrokeFilter::KisLsStrokeFilter()
+    : KisLayerStyleFilter(KoID("lsstroke", i18n("Stroke (style)")))
 {
-    QPen pen(Qt::white, size);
-    KisPainter gc(selection);
-    gc.setPaintColor(KoColor(Qt::white, selection->colorSpace()));
-    gc.drawPainterPath(path, pen, applyRect);
-    gc.end();
 }
 
 void KisLsStrokeFilter::applyStroke(KisPaintDeviceSP srcDevice,
@@ -70,41 +81,30 @@ void KisLsStrokeFilter::applyStroke(KisPaintDeviceSP srcDevice,
 {
     if (applyRect.isEmpty()) return;
 
-    KisSelectionSP baseSelection = new KisSelection(new KisSelectionEmptyBounds(0));
-    KisPixelSelectionSP selection = baseSelection->pixelSelection();
-
-    //selection->convertToQImage(0, QRect(0,0,300,300)).save("0_selection_initial.png");
-
-    QPainterPath strokePath = env->layerOutlineCache();
-    if (strokePath.isEmpty()) return;
+    const QRect needRect = kisGrowRect(applyRect, borderSize(config->position(), config->size()));
 
-    if (config->position() == psd_stroke_center) {
-        paintPathOnSelection(selection, strokePath,
-                             applyRect, config->size());
-    } else if (config->position() == psd_stroke_outside ||
-               config->position() == psd_stroke_inside) {
-
-        paintPathOnSelection(selection, strokePath,
-                                         applyRect, 2 * config->size());
-
-        KisSelectionSP knockOutSelection =
-            KisLsUtils::selectionFromAlphaChannel(srcDevice, applyRect);
-
-        // disabled intentionally, because it creates artifacts on smooth lines
-        // KisLsUtils::findEdge(knockOutSelection->pixelSelection(), applyRect, true);
+    KisSelectionSP baseSelection = KisLsUtils::selectionFromAlphaChannel(srcDevice, needRect);
+    KisPixelSelectionSP selection = baseSelection->pixelSelection();
 
-        if (config->position() == psd_stroke_inside) {
-            knockOutSelection->pixelSelection()->invert();
+    {
+        KisPixelSelectionSP knockOutSelection = new KisPixelSelection(new KisSelectionEmptyBounds(0));
+        knockOutSelection->makeCloneFromRough(selection, needRect);
+
+        if (config->position() == psd_stroke_outside) {
+            KisGaussianKernel::applyDilate(selection, needRect, 2 * config->size(), QBitArray(), 0);
+        } else if (config->position() == psd_stroke_inside) {
+            KisGaussianKernel::applyErodeU8(knockOutSelection, needRect, 2 * config->size(), QBitArray(), 0);
+        } else if (config->position() == psd_stroke_center) {
+            KisGaussianKernel::applyDilate(selection, needRect, config->size(), QBitArray(), 0);
+            KisGaussianKernel::applyErodeU8(knockOutSelection, needRect, config->size(), QBitArray(), 0);
         }
 
         KisPainter gc(selection);
         gc.setCompositeOp(COMPOSITE_ERASE);
-        gc.bitBlt(applyRect.topLeft(), knockOutSelection->pixelSelection(), applyRect);
+        gc.bitBlt(needRect.topLeft(), knockOutSelection, needRect);
         gc.end();
     }
 
-    //selection->convertToQImage(0, QRect(0,0,300,300)).save("1_selection_stroke.png");
-
     KisPaintDeviceSP fillDevice = new KisPaintDevice(srcDevice->colorSpace());
     KisLsUtils::fillOverlayDevice(fillDevice, applyRect, config, env);
 
@@ -138,19 +138,16 @@ void KisLsStrokeFilter::processDirectly(KisPaintDeviceSP src,
     applyStroke(src, dst, applyRect, w.config, env);
 }
 
-QRect KisLsStrokeFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment */*env*/) const
-{
-    Q_UNUSED(style);
-    return rect;
-}
-
-QRect KisLsStrokeFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const
+QRect KisLsStrokeFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const
 {
     const psd_layer_effects_stroke *config = style->stroke();
     if (!config->effectEnabled()) return rect;
 
     KisLsUtils::LodWrapper<psd_layer_effects_stroke> w(env->currentLevelOfDetail(), config);
+    return kisGrowRect(rect, borderSize(w.config->position(), w.config->size()));
+}
 
-    const int borderSize = w.config->size() + 1;
-    return kisGrowRect(rect, borderSize);
+QRect KisLsStrokeFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const
+{
+    return neededRect(rect, style, env);
 }


More information about the kimageshop mailing list