File indexing completed on 2024-05-19 04:26:12
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 <KisRunnableStrokeJobUtils.h> 0021 #include <kis_processing_visitor.h> 0022 0023 #include <kritaimage_export.h> 0024 0025 0026 class KisFilterConfiguration; 0027 0028 // XXX: Filling should set dirty rect. 0029 /** 0030 * This painter can be used to fill paint devices in different ways. This can also be used 0031 * for flood filling related operations. 0032 */ 0033 class KRITAIMAGE_EXPORT KisFillPainter : public KisPainter 0034 { 0035 0036 public: 0037 enum RegionFillingMode 0038 { 0039 RegionFillingMode_FloodFill, 0040 RegionFillingMode_BoundaryFill 0041 }; 0042 0043 /** 0044 * Construct an empty painter. Use the begin(KisPaintDeviceSP) method to attach 0045 * to a paint device 0046 */ 0047 KisFillPainter(); 0048 /** 0049 * Start painting on the specified paint device 0050 */ 0051 KisFillPainter(KisPaintDeviceSP device); 0052 0053 KisFillPainter(KisPaintDeviceSP device, KisSelectionSP selection); 0054 0055 private: 0056 0057 void initFillPainter(); 0058 0059 public: 0060 /** 0061 * Fill current selection of KisPainter with a specified \p color. 0062 * 0063 * The filling rect is limited by \p rc to allow multithreaded 0064 * filling/processing. 0065 */ 0066 void fillSelection(const QRect &rc, const KoColor &color); 0067 0068 /** 0069 * Fill a rectangle with a certain color and opacity. 0070 */ 0071 void fillRect(qint32 x, 0072 qint32 y, 0073 qint32 w, 0074 qint32 h, 0075 const KoColor &c, 0076 quint8 opacity); 0077 0078 /** 0079 * Overloaded version of the above function. 0080 */ 0081 inline void fillRect(const QRect &rc, const KoColor &c, quint8 opacity) 0082 { 0083 fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, opacity); 0084 } 0085 0086 /** 0087 * Fill a rectangle with a certain color. 0088 */ 0089 inline void 0090 fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor &c) 0091 { 0092 fillRect(x, y, w, h, c, OPACITY_OPAQUE_U8); 0093 } 0094 0095 /** 0096 * Overloaded version of the above function. 0097 */ 0098 inline void fillRect(const QRect &rc, const KoColor &c) 0099 { 0100 fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_OPAQUE_U8); 0101 } 0102 0103 /** 0104 * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the 0105 * entire rectangle. 0106 */ 0107 void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoPatternSP pattern, const QPoint &offset = QPoint()); 0108 0109 /** 0110 * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the 0111 * entire rectangle. 0112 * 0113 * This one uses blitting and thus makes use of proper composition. 0114 */ 0115 void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisPaintDeviceSP device, const QRect& deviceRect); 0116 0117 /** 0118 * Overloaded version of the above function. 0119 */ 0120 void fillRect(const QRect &rc, const KisPaintDeviceSP device, const QRect &deviceRect); 0121 0122 /** 0123 * Overloaded version of the above function. 0124 */ 0125 void fillRect(const QRect& rc, const KoPatternSP pattern, const QPoint &offset = QPoint()); 0126 0127 /** 0128 * Fill a rectangle with black transparent pixels (0, 0, 0, 0 for RGBA). 0129 */ 0130 inline void eraseRect(qint32 x1, qint32 y1, qint32 w, qint32 h) 0131 { 0132 const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); 0133 KoColor c(Qt::black, cs); 0134 fillRect(x1, y1, w, h, c, OPACITY_TRANSPARENT_U8); 0135 } 0136 0137 /** 0138 * Overloaded version of the above function. 0139 */ 0140 inline void eraseRect(const QRect &rc) 0141 { 0142 const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); 0143 KoColor c(Qt::black, cs); 0144 fillRect(rc.x(), 0145 rc.y(), 0146 rc.width(), 0147 rc.height(), 0148 c, 0149 OPACITY_TRANSPARENT_U8); 0150 } 0151 0152 /** 0153 * @brief fillRect 0154 * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the 0155 * entire rectangle. Differs from other functions that it uses a transform, does not support 0156 * composite ops in turn. 0157 * @param rc rectangle to fill. 0158 * @param pattern pattern to use. 0159 * @param transform transformation to apply to the pattern. 0160 */ 0161 void fillRectNoCompose(const QRect& rc, const KoPatternSP pattern, const QTransform transform); 0162 0163 /** 0164 * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the 0165 * entire rectangle. 0166 * 0167 * This one supports transforms, but does not use blitting. 0168 */ 0169 void fillRectNoCompose(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisPaintDeviceSP device, const QRect& deviceRect, const QTransform transform); 0170 0171 /** 0172 * Fill the specified area with the output of the generator plugin that is configured 0173 * in the generator parameter 0174 */ 0175 void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisFilterConfigurationSP generator); 0176 0177 /** 0178 * Fills the enclosed area around the point with the set color. If 0179 * there is a selection, the whole selection is filled. Note that 0180 * you must have set the width and height on the painter if you 0181 * don't have a selection. 0182 * 0183 * @param startX the X position where the floodfill starts 0184 * @param startY the Y position where the floodfill starts 0185 * @param sourceDevice the sourceDevice that determines the area that 0186 * is floodfilled if sampleMerged is on 0187 */ 0188 void fillColor(int startX, int startY, KisPaintDeviceSP sourceDevice); 0189 0190 /** 0191 * Fills the enclosed area around the point with the set pattern. 0192 * If there is a selection, the whole selection is filled. Note 0193 * that you must have set the width and height on the painter if 0194 * you don't have a selection. 0195 * 0196 * @param startX the X position where the floodfill starts 0197 * @param startY the Y position where the floodfill starts 0198 * @param sourceDevice the sourceDevice that determines the area that 0199 * is floodfilled if sampleMerged is on 0200 * @param patternTransform transform applied to the pattern; 0201 */ 0202 void fillPattern(int startX, int startY, KisPaintDeviceSP sourceDevice, QTransform patternTransform = QTransform()); 0203 0204 /** 0205 * Returns a selection mask for the floodfill starting at the specified position. 0206 * This variant basically creates a new selection object and passes it down 0207 * to the other variant of the function. 0208 * 0209 * @param startX the X position where the floodfill starts 0210 * @param startY the Y position where the floodfill starts 0211 * @param sourceDevice the sourceDevice that determines the area that 0212 * is floodfilled if sampleMerged is on 0213 */ 0214 KisPixelSelectionSP createFloodSelection(int startX, int startY, 0215 KisPaintDeviceSP sourceDevice, KisPaintDeviceSP existingSelection); 0216 0217 /** 0218 * Returns a selection mask for the floodfill starting at the specified position. 0219 * This variant requires an empty selection object. It is used in cases where the pointer 0220 * to the selection must be known beforehand, for example when the selection is filled 0221 * in a stroke and then the pointer to the pixel selection is needed later. 0222 * 0223 * @param selection empty new selection object 0224 * @param startX the X position where the floodfill starts 0225 * @param startY the Y position where the floodfill starts 0226 * @param sourceDevice the sourceDevice that determines the area that 0227 * is floodfilled if sampleMerged is on 0228 */ 0229 KisPixelSelectionSP createFloodSelection(KisPixelSelectionSP newSelection, int startX, int startY, 0230 KisPaintDeviceSP sourceDevice, KisPaintDeviceSP existingSelection); 0231 0232 /** 0233 * Fills all the pixels of the @ref outSelection device inside @ref rect 0234 * if the corresponding pixels on @ref referenceDevice are similar 0235 * to @ref referenceColor 0236 * 0237 * @param outSelection the selection where the values are written to 0238 * @param referenceColor the color that we have to compare pixels to 0239 * @param referenceDevice the device that we have to use to compare colors 0240 * @param rect the rectangle that defines the area to be processed 0241 * @param mask a selection to mask the results. Set to nullptr if not needed 0242 */ 0243 void createSimilarColorsSelection(KisPixelSelectionSP outSelection, 0244 const KoColor &referenceColor, 0245 KisPaintDeviceSP referenceDevice, 0246 const QRect &rect, 0247 KisPixelSelectionSP mask); 0248 0249 /** 0250 * Create a list of jobs that will fill synchronously all the pixels of the 0251 * @ref outSelection device inside @ref rect if the corresponding pixels 0252 * on @ref referenceDevice are similar to @ref referenceColor. @ref rect 0253 * is splitted into smaller rects if needed, and the painting of each one 0254 * is distributed on several jobs 0255 * 0256 * @param outSelection the selection where the values are written to 0257 * @param referenceColor the color that we have to compare pixels to 0258 * @param referenceDevice the device that we have to use to compare colors 0259 * @param rect the rectangle that defines the area to be processed 0260 * @param mask a selection to mask the results. Set to nullptr if not needed 0261 */ 0262 QVector<KisStrokeJobData*> createSimilarColorsSelectionJobs( 0263 KisPixelSelectionSP outSelection, 0264 const QSharedPointer<KoColor> referenceColor, 0265 KisPaintDeviceSP referenceDevice, 0266 const QRect &rect, 0267 KisPixelSelectionSP mask, 0268 QSharedPointer<KisProcessingVisitor::ProgressHelper> progressHelper = nullptr 0269 ); 0270 0271 /** 0272 * Set the threshold for floodfill. The range is 0-255: 0 means the fill will only 0273 * fill parts that are the exact same color, 255 means anything will be filled 0274 */ 0275 inline void setFillThreshold(int threshold) 0276 { 0277 m_threshold = threshold; 0278 } 0279 0280 /** Returns the fill threshold, see setFillThreshold for details */ 0281 int fillThreshold() const { 0282 return m_threshold; 0283 } 0284 0285 /** 0286 * Set the opacity spread for floodfill. The range is 0-100: 0% means that 0287 * the fully opaque area only encompasses the pixels exactly equal to the 0288 * seed point with the other pixels of the selected region being 0289 * semi-transparent (depending on how similar they are to the seed pixel) 0290 * up to the region boundary (given by the threshold value). 100 means that 0291 * the fully opaque area will encompass all the pixels of the selected 0292 * region up to the contour. Any value in between will make the fully opaque 0293 * portion of the region vary in size, with semi-transparent pixels 0294 * in between it and the region boundary 0295 */ 0296 void setOpacitySpread(int opacitySpread) 0297 { 0298 m_opacitySpread = opacitySpread; 0299 } 0300 0301 /** Returns the fill opacity spread, see setOpacitySpread for details */ 0302 int opacitySpread() const { 0303 return m_opacitySpread; 0304 } 0305 0306 bool useCompositing() const { 0307 return m_useCompositing; 0308 } 0309 0310 void setUseCompositing(bool useCompositing) { 0311 m_useCompositing = useCompositing; 0312 } 0313 0314 /** Sets the width of the paint device */ 0315 void setWidth(int w) { 0316 m_width = w; 0317 } 0318 0319 /** Sets the height of the paint device */ 0320 void setHeight(int h) { 0321 m_height = h; 0322 } 0323 0324 /** If true, floodfill doesn't fill outside the selected area of a layer */ 0325 bool careForSelection() const { 0326 return m_careForSelection; 0327 } 0328 0329 /** Set caring for selection. See careForSelection for details */ 0330 void setCareForSelection(bool set) { 0331 m_careForSelection = set; 0332 } 0333 0334 /** Sets if antiAlias should be applied to the selection */ 0335 void setAntiAlias(bool antiAlias) { 0336 m_antiAlias = antiAlias; 0337 } 0338 0339 /** Get if antiAlias should be applied to the selection */ 0340 bool antiAlias() const { 0341 return m_antiAlias; 0342 } 0343 0344 /** Sets the auto growth/shrinking radius */ 0345 void setSizemod(int sizemod) { 0346 m_sizemod = sizemod; 0347 } 0348 0349 /** Sets how much to auto-grow or shrink (if @p sizemod is negative) the selection 0350 flood before painting, this affects every fill operation except fillRect */ 0351 int sizemod() const { 0352 return m_sizemod; 0353 } 0354 0355 /** Sets feathering radius */ 0356 void setFeather(int feather) { 0357 m_feather = feather; 0358 } 0359 0360 /** defines the feathering radius for selection flood operations, this affects every 0361 fill operation except fillRect */ 0362 uint feather() const { 0363 return m_feather; 0364 } 0365 0366 /** Sets selection borders being treated as boundary */ 0367 void setUseSelectionAsBoundary(bool useSelectionAsBoundary) { 0368 m_useSelectionAsBoundary = useSelectionAsBoundary; 0369 } 0370 0371 /** defines if the selection borders are treated as boundary in flood fill or not */ 0372 uint useSelectionAsBoundary() const { 0373 return m_useSelectionAsBoundary; 0374 } 0375 0376 /** Sets the region filling mode */ 0377 void setRegionFillingMode(RegionFillingMode regionFillingMode) { 0378 m_regionFillingMode = regionFillingMode; 0379 } 0380 0381 /** Gets the region filling mode */ 0382 RegionFillingMode regionFillingMode() const { 0383 return m_regionFillingMode; 0384 } 0385 0386 /** Sets the color of the boundary used when the region filling mode is 0387 * RegionFillingMode_BoundaryFill 0388 */ 0389 void setRegionFillingBoundaryColor(const KoColor ®ionFillingBoundaryColor) { 0390 m_regionFillingBoundaryColor = regionFillingBoundaryColor; 0391 } 0392 0393 /** Gets the color of the boundary used when the region filling mode is 0394 * RegionFillingMode_BoundaryFill 0395 */ 0396 KoColor regionFillingBoundaryColor() const { 0397 return m_regionFillingBoundaryColor; 0398 } 0399 0400 /** 0401 * Sets if the selection should stop growing at the darkest and/or more 0402 * opaque pixel when using a positive grow value (sizemod) 0403 */ 0404 void setStopGrowingAtDarkestPixel(bool stopGrowingAtDarkestPixel) { 0405 m_stopGrowingAtDarkestPixel = stopGrowingAtDarkestPixel; 0406 } 0407 0408 /** 0409 * Gets if the selection should stop growing at the darkest and/or more 0410 * opaque pixel when using a positive grow value (sizemod) 0411 */ 0412 bool stopGrowingAtDarkestPixel() const { 0413 return m_stopGrowingAtDarkestPixel; 0414 } 0415 0416 protected: 0417 void setCurrentFillSelection(KisSelectionSP fillSelection) 0418 { 0419 m_fillSelection = fillSelection; 0420 } 0421 0422 KisSelectionSP currentFillSelection() const 0423 { 0424 return m_fillSelection; 0425 } 0426 0427 // for floodfill 0428 void genericFillStart(int startX, int startY, KisPaintDeviceSP sourceDevice); 0429 void genericFillEnd(KisPaintDeviceSP filled); 0430 0431 private: 0432 KisSelectionSP m_fillSelection; 0433 0434 int m_feather; 0435 int m_sizemod; 0436 bool m_antiAlias; 0437 int m_threshold; 0438 int m_opacitySpread; 0439 int m_width, m_height; 0440 QRect m_rect; 0441 bool m_careForSelection; 0442 bool m_useCompositing; 0443 bool m_useSelectionAsBoundary; 0444 RegionFillingMode m_regionFillingMode; 0445 KoColor m_regionFillingBoundaryColor; 0446 bool m_stopGrowingAtDarkestPixel; 0447 }; 0448 0449 #endif //KIS_FILL_PAINTER_H_