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

0001 /*
0002  *  SPDX-FileCopyrightText: 2004 Adrian Page <adrian@pagenet.plus.com>
0003  *  SPDX-FileCopyrightText: 2004 Bart Coppens <kde@bartcoppens.be>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 #ifndef KIS_FILL_PAINTER_H_
0008 #define KIS_FILL_PAINTER_H_
0009 
0010 #include <QRect>
0011 
0012 #include <KoColor.h>
0013 #include <KoColorSpaceRegistry.h>
0014 #include <KoPattern.h>
0015 
0016 #include "kis_painter.h"
0017 #include "kis_types.h"
0018 #include "kis_selection.h"
0019 
0020 #include <kritaimage_export.h>
0021 
0022 
0023 class KisFilterConfiguration;
0024 
0025 // XXX: Filling should set dirty rect.
0026 /**
0027  * This painter can be used to fill paint devices in different ways. This can also be used
0028  * for flood filling related operations.
0029  */
0030 class KRITAIMAGE_EXPORT KisFillPainter : public KisPainter
0031 {
0032 
0033 public:
0034 
0035     /**
0036      * Construct an empty painter. Use the begin(KisPaintDeviceSP) method to attach
0037      * to a paint device
0038      */
0039     KisFillPainter();
0040     /**
0041      * Start painting on the specified paint device
0042      */
0043     KisFillPainter(KisPaintDeviceSP device);
0044 
0045     KisFillPainter(KisPaintDeviceSP device, KisSelectionSP selection);
0046 
0047 private:
0048 
0049     void initFillPainter();
0050 
0051 public:
0052     /**
0053      * Fill current selection of KisPainter with a specified \p color.
0054      *
0055      * The filling rect is limited by \p rc to allow multithreaded
0056      * filling/processing.
0057      */
0058     void fillSelection(const QRect &rc, const KoColor &color);
0059 
0060     /**
0061      * Fill a rectangle with a certain color and opacity.
0062      */
0063     void fillRect(qint32 x,
0064                   qint32 y,
0065                   qint32 w,
0066                   qint32 h,
0067                   const KoColor &c,
0068                   quint8 opacity);
0069 
0070     /**
0071      * Overloaded version of the above function.
0072      */
0073     inline void fillRect(const QRect &rc, const KoColor &c, quint8 opacity)
0074     {
0075         fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, opacity);
0076     }
0077 
0078     /**
0079      * Fill a rectangle with a certain color.
0080      */
0081     inline void
0082     fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor &c)
0083     {
0084         fillRect(x, y, w, h, c, OPACITY_OPAQUE_U8);
0085     }
0086 
0087     /**
0088      * Overloaded version of the above function.
0089      */
0090     inline void fillRect(const QRect &rc, const KoColor &c)
0091     {
0092         fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_OPAQUE_U8);
0093     }
0094 
0095     /**
0096      * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the
0097      * entire rectangle.
0098      */
0099     void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoPatternSP pattern, const QPoint &offset = QPoint());
0100 
0101     /**
0102      * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the
0103      * entire rectangle.
0104      *
0105      * This one uses blitting and thus makes use of proper composition.
0106      */
0107     void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisPaintDeviceSP device, const QRect& deviceRect);
0108 
0109     /**
0110      * Overloaded version of the above function.
0111      */
0112     void fillRect(const QRect &rc, const KisPaintDeviceSP device, const QRect &deviceRect);
0113 
0114     /**
0115      * Overloaded version of the above function.
0116      */
0117     void fillRect(const QRect& rc, const KoPatternSP pattern, const QPoint &offset = QPoint());
0118 
0119     /**
0120      * Fill a rectangle with black transparent pixels (0, 0, 0, 0 for RGBA).
0121      */
0122     inline void eraseRect(qint32 x1, qint32 y1, qint32 w, qint32 h)
0123     {
0124         const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
0125         KoColor c(Qt::black, cs);
0126         fillRect(x1, y1, w, h, c, OPACITY_TRANSPARENT_U8);
0127     }
0128 
0129     /**
0130      * Overloaded version of the above function.
0131      */
0132     inline void eraseRect(const QRect &rc)
0133     {
0134         const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
0135         KoColor c(Qt::black, cs);
0136         fillRect(rc.x(),
0137                  rc.y(),
0138                  rc.width(),
0139                  rc.height(),
0140                  c,
0141                  OPACITY_TRANSPARENT_U8);
0142     }
0143 
0144     /**
0145      * @brief fillRect
0146      * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the
0147      * entire rectangle. Differs from other functions that it uses a transform, does not support
0148      * composite ops in turn.
0149      * @param rc rectangle to fill.
0150      * @param pattern pattern to use.
0151      * @param transform transformation to apply to the pattern.
0152      */
0153     void fillRectNoCompose(const QRect& rc, const KoPatternSP pattern, const QTransform transform);
0154 
0155     /**
0156      * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the
0157      * entire rectangle.
0158      *
0159      * This one supports transforms, but does not use blitting.
0160      */
0161     void fillRectNoCompose(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisPaintDeviceSP device, const QRect& deviceRect, const QTransform transform);
0162 
0163     /**
0164      * Fill the specified area with the output of the generator plugin that is configured
0165      * in the generator parameter
0166      */
0167     void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisFilterConfigurationSP  generator);
0168 
0169     /**
0170      * Fills the enclosed area around the point with the set color. If
0171      * there is a selection, the whole selection is filled. Note that
0172      * you must have set the width and height on the painter if you
0173      * don't have a selection.
0174      *
0175      * @param startX the X position where the floodfill starts
0176      * @param startY the Y position where the floodfill starts
0177      * @param sourceDevice the sourceDevice that determines the area that
0178      * is floodfilled if sampleMerged is on
0179      */
0180     void fillColor(int startX, int startY, KisPaintDeviceSP sourceDevice);
0181 
0182     /**
0183      * Fills the enclosed area around the point with the set pattern.
0184      * If there is a selection, the whole selection is filled. Note
0185      * that you must have set the width and height on the painter if
0186      * you don't have a selection.
0187      *
0188      * @param startX the X position where the floodfill starts
0189      * @param startY the Y position where the floodfill starts
0190      * @param sourceDevice the sourceDevice that determines the area that
0191      * is floodfilled if sampleMerged is on
0192      * @param patternTransform transform applied to the pattern;
0193      */
0194     void fillPattern(int startX, int startY, KisPaintDeviceSP sourceDevice, QTransform patternTransform = QTransform());
0195 
0196     /**
0197      * Returns a selection mask for the floodfill starting at the specified position.
0198      * This variant basically creates a new selection object and passes it down
0199      *   to the other variant of the function.
0200      *
0201      * @param startX the X position where the floodfill starts
0202      * @param startY the Y position where the floodfill starts
0203      * @param sourceDevice the sourceDevice that determines the area that
0204      * is floodfilled if sampleMerged is on
0205      */
0206     KisPixelSelectionSP createFloodSelection(int startX, int startY,
0207                                              KisPaintDeviceSP sourceDevice, KisPaintDeviceSP existingSelection);
0208 
0209     /**
0210      * Returns a selection mask for the floodfill starting at the specified position.
0211      * This variant requires an empty selection object. It is used in cases where the pointer
0212      *    to the selection must be known beforehand, for example when the selection is filled
0213      *    in a stroke and then the pointer to the pixel selection is needed later.
0214      *
0215      * @param selection empty new selection object
0216      * @param startX the X position where the floodfill starts
0217      * @param startY the Y position where the floodfill starts
0218      * @param sourceDevice the sourceDevice that determines the area that
0219      * is floodfilled if sampleMerged is on
0220      */
0221     KisPixelSelectionSP createFloodSelection(KisPixelSelectionSP newSelection, int startX, int startY,
0222                                              KisPaintDeviceSP sourceDevice, KisPaintDeviceSP existingSelection);
0223 
0224     /**
0225      * Set the threshold for floodfill. The range is 0-255: 0 means the fill will only
0226      * fill parts that are the exact same color, 255 means anything will be filled
0227      */
0228     inline void setFillThreshold(int threshold)
0229     {
0230         m_threshold = threshold;
0231     }
0232 
0233     /** Returns the fill threshold, see setFillThreshold for details */
0234     int fillThreshold() const {
0235         return m_threshold;
0236     }
0237 
0238     /**
0239      * Set the opacity spread for floodfill. The range is 0-100: 0% means that
0240      * the fully opaque area only encompasses the pixels exactly equal to the
0241      * seed point with the other pixels of the selected region being
0242      * semi-transparent (depending on how similar they are to the seed pixel)
0243      * up to the region boundary (given by the threshold value). 100 means that
0244      * the fully opaque area will encompass all the pixels of the selected
0245      * region up to the contour. Any value inbetween will make the fully opaque
0246      * portion of the region vary in size, with semi-transparent pixels
0247      * inbetween it and  the region boundary
0248      */
0249     void setOpacitySpread(int opacitySpread)
0250     {
0251         m_opacitySpread = opacitySpread;
0252     }
0253 
0254     /** Returns the fill opacity spread, see setOpacitySpread for details */
0255     int opacitySpread() const {
0256         return m_opacitySpread;
0257     }
0258 
0259     bool useCompositioning() const {
0260         return m_useCompositioning;
0261     }
0262 
0263     void setUseCompositioning(bool useCompositioning) {
0264         m_useCompositioning = useCompositioning;
0265     }
0266 
0267     /** Sets the width of the paint device */
0268     void setWidth(int w) {
0269         m_width = w;
0270     }
0271 
0272     /** Sets the height of the paint device */
0273     void setHeight(int h) {
0274         m_height = h;
0275     }
0276 
0277     /** If true, floodfill doesn't fill outside the selected area of a layer */
0278     bool careForSelection() const {
0279         return m_careForSelection;
0280     }
0281 
0282     /** Set caring for selection. See careForSelection for details */
0283     void setCareForSelection(bool set) {
0284         m_careForSelection = set;
0285     }
0286 
0287     /** Sets if antiAlias should be applied to the selection */
0288     void setAntiAlias(bool antiAlias) {
0289         m_antiAlias = antiAlias;
0290     }
0291     
0292     /** Get if antiAlias should be applied to the selection */
0293     bool antiAlias() const {
0294         return m_antiAlias;
0295     }
0296 
0297     /** Sets the auto growth/shrinking radius */
0298     void setSizemod(int sizemod) {
0299         m_sizemod = sizemod;
0300     }
0301     
0302     /** Sets how much to auto-grow or shrink (if @p sizemod is negative) the selection
0303     flood before painting, this affects every fill operation except fillRect */
0304     int sizemod() const {
0305         return m_sizemod;
0306     }
0307     
0308     /** Sets feathering radius */
0309     void setFeather(int feather) {
0310         m_feather = feather;
0311     }
0312     
0313     /** defines the feathering radius for selection flood operations, this affects every
0314     fill operation except fillRect */
0315     uint feather() const {
0316         return m_feather;
0317     }
0318 
0319     /** Sets selection borders being treated as boundary */
0320     void setUseSelectionAsBoundary(bool useSelectionAsBoundary) {
0321         m_useSelectionAsBoundary = useSelectionAsBoundary;
0322     }
0323 
0324     /** defines if the selection borders are treated as boundary in flood fill or not */
0325     uint useSelectionAsBoundary() const {
0326         return m_useSelectionAsBoundary;
0327     }
0328 
0329 protected:
0330     void setCurrentFillSelection(KisSelectionSP fillSelection)
0331     {
0332         m_fillSelection = fillSelection;
0333     }
0334 
0335     KisSelectionSP currentFillSelection() const
0336     {
0337         return m_fillSelection;
0338     }
0339 
0340     // for floodfill
0341     void genericFillStart(int startX, int startY, KisPaintDeviceSP sourceDevice);
0342     void genericFillEnd(KisPaintDeviceSP filled);
0343 
0344 private:
0345     KisSelectionSP m_fillSelection;
0346 
0347     int m_feather;
0348     int m_sizemod;
0349     bool m_antiAlias;
0350     int m_threshold;
0351     int m_opacitySpread;
0352     int m_width, m_height;
0353     QRect m_rect;
0354     bool m_careForSelection;
0355     bool m_useCompositioning;
0356     bool m_useSelectionAsBoundary;
0357 };
0358 
0359 #endif //KIS_FILL_PAINTER_H_