File indexing completed on 2024-05-12 15:58:42

0001 /*
0002  *  SPDX-FileCopyrightText: 2005 Michael Thaler
0003  *  SPDX-FileCopyrightText: 2011 Dmitry Kazakov <dimula73@gmail.com>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 
0009 #ifndef KIS_SELECTION_FILTERS_H
0010 #define KIS_SELECTION_FILTERS_H
0011 
0012 #include "kis_types.h"
0013 #include "kritaimage_export.h"
0014 #include "kis_default_bounds_base.h"
0015 
0016 #include <QRect>
0017 #include <QString>
0018 
0019 class KUndo2MagicString;
0020 
0021 
0022 class KRITAIMAGE_EXPORT KisSelectionFilter
0023 {
0024 public:
0025     virtual ~KisSelectionFilter();
0026 
0027     virtual void process(KisPixelSelectionSP pixelSelection,
0028                          const QRect &rect) = 0;
0029 
0030     virtual KUndo2MagicString name();
0031     virtual QRect changeRect(const QRect &rect, KisDefaultBoundsBaseSP defaultBounds);
0032 
0033 protected:
0034     void computeBorder(qint32  *circ, qint32  xradius, qint32  yradius);
0035 
0036     void rotatePointers(quint8  **p, quint32 n);
0037 
0038     void computeTransition(quint8* transition, quint8** buf, qint32 width);
0039 };
0040 
0041 class KRITAIMAGE_EXPORT KisErodeSelectionFilter : public KisSelectionFilter
0042 {
0043 public:
0044     KUndo2MagicString name() override;
0045 
0046     QRect changeRect(const QRect &rect, KisDefaultBoundsBaseSP defaultBounds) override;
0047 
0048     void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override;
0049 };
0050 
0051 class KRITAIMAGE_EXPORT KisDilateSelectionFilter : public KisSelectionFilter
0052 {
0053 public:
0054     KUndo2MagicString name() override;
0055 
0056     QRect changeRect(const QRect &rect, KisDefaultBoundsBaseSP defaultBounds) override;
0057 
0058     void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override;
0059 };
0060 
0061 class KRITAIMAGE_EXPORT KisBorderSelectionFilter : public KisSelectionFilter
0062 {
0063 public:
0064     KisBorderSelectionFilter(qint32 xRadius, qint32 yRadius, bool fade);
0065 
0066     KUndo2MagicString name() override;
0067 
0068     QRect changeRect(const QRect &rect, KisDefaultBoundsBaseSP defaultBounds) override;
0069 
0070     void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override;
0071 
0072 private:
0073     qint32 m_xRadius;
0074     qint32 m_yRadius;
0075     bool m_antialiasing;
0076 };
0077 
0078 class KRITAIMAGE_EXPORT KisFeatherSelectionFilter : public KisSelectionFilter
0079 {
0080 public:
0081     KisFeatherSelectionFilter(qint32 radius);
0082 
0083     KUndo2MagicString name() override;
0084 
0085     QRect changeRect(const QRect &rect, KisDefaultBoundsBaseSP defaultBounds) override;
0086 
0087     void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override;
0088 private:
0089     qint32 m_radius;
0090 };
0091 
0092 class KRITAIMAGE_EXPORT KisGrowSelectionFilter : public KisSelectionFilter
0093 {
0094 public:
0095     KisGrowSelectionFilter(qint32 xRadius, qint32 yRadius);
0096 
0097     KUndo2MagicString name() override;
0098 
0099     QRect changeRect(const QRect &rect, KisDefaultBoundsBaseSP defaultBounds) override;
0100 
0101     void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override;
0102 
0103 private:
0104     qint32 m_xRadius;
0105     qint32 m_yRadius;
0106 };
0107 
0108 class KRITAIMAGE_EXPORT KisShrinkSelectionFilter : public KisSelectionFilter
0109 {
0110 public:
0111     KisShrinkSelectionFilter(qint32 xRadius, qint32 yRadius, bool edgeLock);
0112 
0113     KUndo2MagicString name() override;
0114 
0115     QRect changeRect(const QRect &rect, KisDefaultBoundsBaseSP defaultBounds) override;
0116 
0117     void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override;
0118 
0119 private:
0120     qint32 m_xRadius;
0121     qint32 m_yRadius;
0122     qint32 m_edgeLock;
0123 };
0124 
0125 class KRITAIMAGE_EXPORT KisSmoothSelectionFilter : public KisSelectionFilter
0126 {
0127 public:
0128     KUndo2MagicString name() override;
0129 
0130     QRect changeRect(const QRect &rect, KisDefaultBoundsBaseSP defaultBounds) override;
0131 
0132     void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override;
0133 };
0134 
0135 class KRITAIMAGE_EXPORT KisInvertSelectionFilter : public KisSelectionFilter
0136 {
0137 public:
0138     KUndo2MagicString name() override;
0139 
0140     QRect changeRect(const QRect &rect, KisDefaultBoundsBaseSP defaultBounds) override;
0141 
0142     void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override;
0143 };
0144 
0145 /**
0146  * @brief AntiAlias filter for selections inspired by FXAA 
0147  */
0148 class KRITAIMAGE_EXPORT KisAntiAliasSelectionFilter : public KisSelectionFilter
0149 {
0150 public:
0151     KUndo2MagicString name() override;
0152     void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override;
0153 
0154 private:
0155     /**
0156      * @brief Edges with gradient less than this value will not be antiAliasied
0157      */
0158     static constexpr qint32 edgeThreshold {4};
0159     /**
0160      * @brief Number of steps to jump when searching for one of the ends of the
0161      *        antiAliased span.
0162      */
0163     static constexpr qint32 numSteps {30};
0164     /**
0165      * @brief This array of @ref numSteps size holds the number of pixels to
0166      *        jump in each step.
0167      */
0168     static constexpr qint32 offsets[numSteps] {
0169         1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0170         1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0171         2, 2, 2, 2, 2, 2, 2, 2, 2, 2
0172     };
0173     /**
0174      * @brief The size of the border added internally to the left and right of
0175      *        the scanline buffer so that we can read outside the selection rect
0176      *        without problems. It must be equal to the largest value in @ref offsets. 
0177      */
0178     static constexpr qint32 horizontalBorderSize {2};
0179     /**
0180      * @brief The size of the border added internally to the top and bottom of
0181      *        the scanline buffer so that we can read outside the selection rect
0182      *        without problems. It must be equal to the sum of all values in @ref offsets. 
0183      */
0184     static constexpr qint32 verticalBorderSize {40};
0185     /**
0186      * @brief Number of scanlines in the internal buffer.
0187      */
0188     static constexpr qint32 numberOfScanlines {2 * verticalBorderSize + 1};
0189     /**
0190      * @brief Offset of the current scanline in the buffer (The middle scanline).
0191      */
0192     static constexpr qint32 currentScanlineIndex {verticalBorderSize};
0193     /**
0194      * @brief Get a interpolation value to linearly interpolate the current
0195      *        pixel with its edge neighbor.
0196      * @return true if we must apply the interpolation. false otherwise.
0197      */
0198     bool getInterpolationValue(qint32 negativeSpanEndDistance, qint32 positiveSpanEndDistance,
0199                                qint32 negativePixelDiff, qint32 positivePixelDiff, qint32 currentPixelDiff,
0200                                bool negativeSpanExtremeValid, bool positiveSpanExtremeValid,
0201                                qint32 *interpolationValue) const;
0202     /**
0203      * @brief Get the extreme point of the span for the current pixel in the 
0204      *        given direction
0205      */
0206     void findSpanExtreme(quint8 **scanlines, qint32 x, qint32 pixelOffset,
0207                          qint32 rowMultiplier, qint32 colMultiplier, qint32 direction,
0208                          qint32 pixelAvg, qint32 scaledGradient, qint32 currentPixelDiff,
0209                          qint32 *spanEndDistance, qint32 *pixelDiff, bool *spanExtremeValidType) const;
0210     /**
0211      * @brief Get the extreme points of the span for the current pixel
0212      */
0213     void findSpanExtremes(quint8 **scanlines, qint32 x, qint32 pixelOffset,
0214                           qint32 rowMultiplier, qint32 colMultiplier,
0215                           qint32 pixelAvg, qint32 scaledGradient, qint32 currentPixelDiff,
0216                           qint32 *negativeSpanEndDistance, qint32 *positiveSpanEndDistance,
0217                           qint32 *negativePixelDiff, qint32 *positivePixelDiff,
0218                           bool *negativeSpanExtremeValid, bool *positiveSpanExtremeValid) const;
0219 };
0220 
0221 #endif // KIS_SELECTION_FILTERS_H