Krita Source Code Documentation
Loading...
Searching...
No Matches
KisEncloseAndFillPainter.cpp
Go to the documentation of this file.
1/*
2 * KDE. Krita Project.
3 *
4 * SPDX-FileCopyrightText: 2022 Deif Lou <ginoba@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include <krita_utils.h>
12#include <kis_iterator_ng.h>
13#include <KoUpdater.h>
14#include <kis_default_bounds.h>
16
18
20
26
28 {
32 // differences in the range [0, 100]
33 quint8 getDifferenceFor(const quint8 *srcData) const
34 {
35 return static_cast<quint8>(colorSpace->opacityU8(srcData) * 100 / quint8_MAX);
36 }
37 };
38
40 {
44 // differences in the range [0, 100]
45 quint8 getDifferenceFor(const quint8 *srcData) const
46 {
47 return colorSpace->differenceA(srcData, color.data());
48 }
49 };
50
52 {
56 // differences in the range [0, 100]
57 quint8 getDifferenceFor(const quint8 *srcData) const
58 {
59 const quint8 opacity = colorSpace->opacityU8(srcData);
60 if (opacity == quint8_MAX) {
61 return 100;
62 }
63 const quint8 colorDifference = colorSpace->difference(srcData, color.data());
64 const quint8 opacityDifference = opacity * 100 / quint8_MAX;
65 return qMin(colorDifference, opacityDifference);
66 }
67 };
68
70 {
74 // differences in the range [0, 100]
75 quint8 getDifferenceFor(const quint8 *srcData) const
76 {
77 const quint8 colorDifference = colorSpace->difference(srcData, color.data());
78 const quint8 opacityDifference = colorSpace->opacityU8(srcData) * 100 / quint8_MAX;
79 return qMin(colorDifference, opacityDifference);
80 }
81 };
82
83 template <typename DifferencePolicy>
84 struct HardSelectionPolicy : public DifferencePolicy
85 {
86 const int threshold;
87 HardSelectionPolicy(const KoColorSpace *colorSpace, const KoColor &color, int threshold)
88 : DifferencePolicy(colorSpace, color)
90 {}
91 // differences in the range [0, 100]
92 quint8 getSelectionFor(const quint8 *srcData) const
93 {
94 return this->getDifferenceFor(srcData) <= threshold ? MAX_SELECTED : MIN_SELECTED;
95 }
96 };
97
98 template <typename DifferencePolicy>
99 struct SoftSelectionPolicy : public DifferencePolicy
100 {
101 const int threshold;
102 const int softness;
103 SoftSelectionPolicy(const KoColorSpace *colorSpace, const KoColor &color, int threshold, int softness)
104 : DifferencePolicy(colorSpace, color)
107 {}
108 // differences in the range [0, 100]
109 quint8 getSelectionFor(const quint8 *srcData) const
110 {
111 if (threshold == 0) {
112 return MIN_SELECTED;
113 }
114 // Integer version of: (threshold - diff) / (threshold * softness)
115 const int diff = this->getDifferenceFor(srcData);
116 if (diff < threshold) {
117 const int v = (threshold - diff) * MAX_SELECTED * 100 / (threshold * softness);
118 return v > MAX_SELECTED ? MAX_SELECTED : v;
119 } else {
120 return MIN_SELECTED;
121 }
122 }
123 };
124};
125
127{
128public:
136
138
140 QRect *resultMaskRect,
141 KisPixelSelectionSP enclosingMask,
142 const QRect &enclosingMaskRect,
143 KisPaintDeviceSP referenceDevice) const;
144
146 QRect *resultMaskRect,
147 KisPixelSelectionSP enclosingMask,
148 const QRect &enclosingMaskRect,
149 KisPaintDeviceSP referenceDevice) const;
150
152 QRect *resultMaskRect,
153 KisPixelSelectionSP enclosingMask,
154 const QRect &enclosingMaskRect,
155 KisPaintDeviceSP referenceDevice) const;
157 QRect *resultMaskRect,
158 KisPixelSelectionSP enclosingMask,
159 const QRect &enclosingMaskRect,
160 KisPaintDeviceSP referenceDevice) const;
162 QRect *resultMaskRect,
163 KisPixelSelectionSP enclosingMask,
164 const QRect &enclosingMaskRect,
165 KisPaintDeviceSP referenceDevice) const;
166 template <typename SelectionPolicy>
168 QRect *resultMaskRect,
169 KisPixelSelectionSP enclosingMask,
170 const QRect &enclosingMaskRect,
171 KisPaintDeviceSP referenceDevice,
172 SelectionPolicy selectionPolicy) const;
173
175 QRect *resultMaskRect,
176 KisPixelSelectionSP enclosingMask,
177 const QRect &enclosingMaskRect,
178 KisPaintDeviceSP referenceDevice) const;
180 QRect *resultMaskRect,
181 KisPixelSelectionSP enclosingMask,
182 const QRect &enclosingMaskRect,
183 KisPaintDeviceSP referenceDevice) const;
185 QRect *resultMaskRect,
186 KisPixelSelectionSP enclosingMask,
187 const QRect &enclosingMaskRect,
188 KisPaintDeviceSP referenceDevice) const;
189 template <typename SelectionPolicy>
191 QRect *resultMaskRect,
192 KisPixelSelectionSP enclosingMask,
193 const QRect &enclosingMaskRect,
194 KisPaintDeviceSP referenceDevice,
195 SelectionPolicy selectionPolicy) const;
196
198 QRect *resultMaskRect,
199 KisPixelSelectionSP enclosingMask,
200 const QRect &enclosingMaskRect,
201 KisPaintDeviceSP referenceDevice) const;
203 QRect *resultMaskRect,
204 KisPixelSelectionSP enclosingMask,
205 const QRect &enclosingMaskRect,
206 KisPaintDeviceSP referenceDevice) const;
208 QRect *resultMaskRect,
209 KisPixelSelectionSP enclosingMask,
210 const QRect &enclosingMaskRect,
211 KisPaintDeviceSP referenceDevice) const;
212 template <typename SelectionPolicy>
214 QRect *resultMaskRect,
215 KisPixelSelectionSP enclosingMask,
216 const QRect &enclosingMaskRect,
217 KisPaintDeviceSP referenceDevice,
218 SelectionPolicy selectionPolicy,
219 bool colorOrTransparent = false) const;
220
222 const QRect &enclosingMaskRect) const;
223
225 KisPaintDeviceSP referenceDevice) const;
226
227 void invertIfNeeded(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect) const;
228
229 template <typename SelectionPolicy>
231 KisPixelSelectionSP enclosingMask,
232 const QRect &enclosingMaskRect,
233 KisPaintDeviceSP referenceDevice,
234 SelectionPolicy selectionPolicy) const;
235 template <typename SelectionPolicy>
237 KisPixelSelectionSP enclosingMask,
238 const QRect &enclosingMaskRect,
239 KisPaintDeviceSP referenceDevice,
240 SelectionPolicy selectionPolicy) const;
241
243 KisPixelSelectionSP enclosingMask,
244 const QRect &enclosingMaskRect,
245 KisPaintDeviceSP referenceDevice) const;
247 KisPixelSelectionSP enclosingMask,
248 const QVector<QPoint> &enclosingPoints,
249 const QRect &enclosingMaskRect,
250 KisPaintDeviceSP referenceDevice) const;
251
253 KisPixelSelectionSP enclosingMask,
254 const QRect &enclosingMaskRect,
255 KisPaintDeviceSP referenceDevice,
256 const KoColor &color) const;
258 KisPixelSelectionSP enclosingMask,
259 const QVector<QPoint> &enclosingPoints,
260 const QRect &enclosingMaskRect,
261 KisPaintDeviceSP referenceDevice,
262 const KoColor &color) const;
263
265 KisPixelSelectionSP enclosingMask,
266 const QRect &enclosingMaskRect,
267 KisPaintDeviceSP referenceDevice,
268 const KoColor &color) const;
270 KisPixelSelectionSP enclosingMask,
271 const QVector<QPoint> &enclosingPoints,
272 const QRect &enclosingMaskRect,
273 KisPaintDeviceSP referenceDevice,
274 const KoColor &color) const;
275
277 KisPixelSelectionSP enclosingMask,
278 const QRect &enclosingMaskRect,
279 KisPaintDeviceSP referenceDevice) const;
281 KisPixelSelectionSP enclosingMask,
282 const QVector<QPoint> &enclosingPoints,
283 const QRect &enclosingMaskRect,
284 KisPaintDeviceSP referenceDevice) const;
285
286 void invertMaskRect(KisPixelSelectionSP resultMask, const QRect &rect) const;
287
288};
289
291 : m_d(new Private(this))
292{
293 setWidth(imageSize.width());
294 setHeight(imageSize.height());
295 m_d->imageRect = QRect(QPoint(0, 0), imageSize);
296}
297
299 : KisFillPainter(device)
300 , m_d(new Private(this))
301{
302 setWidth(imageSize.width());
303 setHeight(imageSize.height());
304 m_d->imageRect = QRect(QPoint(0, 0), imageSize);
305}
306
308 : KisFillPainter(device, selection)
309 , m_d(new Private(this))
310{
311 setWidth(imageSize.width());
312 setHeight(imageSize.height());
313 m_d->imageRect = QRect(QPoint(0, 0), imageSize);
314}
315
318
320{
321 genericEncloseAndFillStart(enclosingMask, referenceDevice);
322
324 if (fillRect.isEmpty()) {
325 return;
326 }
327
328 // Now create a layer and fill it
330 Q_CHECK_PTR(filled);
331 KisFillPainter painter(filled);
332 painter.fillRect(fillRect, paintColor());
333 painter.end();
334
336}
337
339 KisPaintDeviceSP referenceDevice,
340 QTransform patternTransform)
341{
342 genericEncloseAndFillStart(enclosingMask, referenceDevice);
343
345 if (fillRect.isEmpty()) {
346 return;
347 }
348
349 // Now create a layer and fill it
351 Q_CHECK_PTR(filled);
352 KisFillPainter painter(filled);
354 painter.end();
355
357}
358
360{
361 // Create a selection from the closed regions
362 KisPixelSelectionSP pixelSelection = createEncloseAndFillSelection(enclosingMask, referenceDevice,
363 (selection().isNull() ? 0 : selection()->pixelSelection()));
364 KisSelectionSP newSelection = new KisSelection(pixelSelection->defaultBounds(), KisImageResolutionProxy::identity());
365 newSelection->pixelSelection()->applySelection(pixelSelection, SELECTION_REPLACE);
366 setCurrentFillSelection(newSelection);
367}
368
373
375 KisPaintDeviceSP referenceDevice,
376 KisPixelSelectionSP existingSelection)
377{
379 return createEncloseAndFillSelection(newSelection, enclosingMask, referenceDevice, existingSelection);
380}
381
383 KisPixelSelectionSP enclosingMask,
384 KisPaintDeviceSP referenceDevice,
385 KisPixelSelectionSP existingSelection)
386{
387 Q_ASSERT(newSelection);
388 Q_ASSERT(enclosingMask);
389 Q_ASSERT(referenceDevice);
390
391 const QRect enclosingMaskRect = enclosingMask->selectedExactRect();
392 if (enclosingMaskRect.isEmpty()) {
393 return newSelection;
394 }
395 QRect newSelectionRect;
396 // Get the mask that includes all the closed regions inside the enclosing mask
397 m_d->computeEnclosedRegionsMask(newSelection, &newSelectionRect, enclosingMask, enclosingMaskRect, referenceDevice);
398 if (newSelectionRect.isEmpty()) {
399 return newSelection;
400 }
401 // Invert
402 m_d->invertIfNeeded(newSelection, enclosingMask, enclosingMaskRect);
403 // Intersect the regions mask with the current selection if it should be used as boundary
404 if (useSelectionAsBoundary() && existingSelection) {
405 newSelection->applySelection(existingSelection, SELECTION_INTERSECT);
406 }
407 // Post-process
408 m_d->applyPostProcessing(newSelection, referenceDevice);
409
410 return newSelection;
411}
412
414{
415 m_d->regionSelectionMethod = regionSelectionMethod;
416}
417
422
424{
425 m_d->regionSelectionColor = color;
426}
427
429{
430 return m_d->regionSelectionColor;
431}
432
434{
435 m_d->regionSelectionInvert = invert;
436}
437
439{
440 return m_d->regionSelectionInvert;
441}
442
444{
445 m_d->regionSelectionIncludeContourRegions = include;
446}
447
449{
450 return m_d->regionSelectionIncludeContourRegions;
451}
452
454{
455 m_d->regionSelectionIncludeSurroundingRegions = include;
456}
457
459{
460 return m_d->regionSelectionIncludeSurroundingRegions;
461}
462
464 QRect *resultMaskRect,
465 KisPixelSelectionSP enclosingMask,
466 const QRect &enclosingMaskRect,
467 KisPaintDeviceSP referenceDevice) const
468{
469 // Create the regions mask
470 switch (regionSelectionMethod) {
471 case SelectAllRegions:
472 selectAllRegions(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
473 break;
475 selectRegionsFilledWithSpecificColor(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
476 break;
478 selectRegionsFilledWithTransparent(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
479 break;
481 selectRegionsFilledWithSpecificColorOrTransparent(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
482 break;
484 selectAllRegionsExceptFilledWithSpecificColor(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
485 break;
487 selectAllRegionsExceptFilledWithTransparent(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
488 break;
490 selectAllRegionsExceptFilledWithSpecificColorOrTransparent(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
491 break;
493 selectRegionsSurroundedBySpecificColor(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
494 break;
496 selectRegionsSurroundedByTransparent(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
497 break;
499 selectRegionsSurroundedBySpecificColorOrTransparent(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice);
500 break;
501 default: return;
502 }
503}
504
506 QRect *resultMaskRect,
507 KisPixelSelectionSP enclosingMask,
508 const QRect &enclosingMaskRect,
509 KisPaintDeviceSP referenceDevice) const
510{
512 // Nothing is selected in this case, so return early
513 return;
514 }
515 resultMask->applySelection(enclosingMask, SELECTION_REPLACE);
518 selectRegionsFromContour(mask, enclosingMask, enclosingMaskRect, referenceDevice);
519 resultMask->applySelection(mask, SELECTION_SUBTRACT);
520 }
521 if (resultMaskRect) {
522 *resultMaskRect = resultMask->selectedExactRect();
523 }
524}
525
527 QRect *resultMaskRect,
528 KisPixelSelectionSP enclosingMask,
529 const QRect &enclosingMaskRect,
530 KisPaintDeviceSP referenceDevice) const
531{
532 using namespace KisEncloseAndFillPainterDetail;
533 const int softness = 100 - q->opacitySpread();
534 if (softness == 0) {
535 HardSelectionPolicy<SpecificColorDifferencePolicy> policy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold());
536 selectRegionsFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
537 } else {
538 SoftSelectionPolicy<SpecificColorDifferencePolicy> policy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold(), softness);
539 selectRegionsFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
540 }
541}
542
544 QRect *resultMaskRect,
545 KisPixelSelectionSP enclosingMask,
546 const QRect &enclosingMaskRect,
547 KisPaintDeviceSP referenceDevice) const
548{
549 using namespace KisEncloseAndFillPainterDetail;
550 const int softness = 100 - q->opacitySpread();
551 if (softness == 0) {
552 HardSelectionPolicy<TransparentDifferencePolicy> policy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold());
553 selectRegionsFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
554 } else {
555 SoftSelectionPolicy<TransparentDifferencePolicy> policy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold(), softness);
556 selectRegionsFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
557 }
558}
559
561 QRect *resultMaskRect,
562 KisPixelSelectionSP enclosingMask,
563 const QRect &enclosingMaskRect,
564 KisPaintDeviceSP referenceDevice) const
565{
566 using namespace KisEncloseAndFillPainterDetail;
567 const int softness = 100 - q->opacitySpread();
568 // Here we must compute the specific color and transparent masks separately
569 // so that the contour regions can be removed independently if they are
570 // transparent or of the specific color and are connected
571 KisPixelSelectionSP resultMaskTransparent = new KisPixelSelection(new KisSelectionDefaultBounds(resultMask));
572 if (softness == 0) {
573 HardSelectionPolicy<SpecificColorDifferencePolicy> colorPolicy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold());
574 selectRegionsFilledWithSpecificColorGeneric(resultMask, nullptr, enclosingMask, enclosingMaskRect, referenceDevice, colorPolicy);
575 HardSelectionPolicy<TransparentForHalosDifferencePolicy> transparentPolicy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold());
576 selectRegionsFilledWithSpecificColorGeneric(resultMaskTransparent, nullptr, enclosingMask, enclosingMaskRect, referenceDevice, transparentPolicy);
577 } else {
578 SoftSelectionPolicy<SpecificColorDifferencePolicy> colorPolicy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold(), softness);
579 selectRegionsFilledWithSpecificColorGeneric(resultMask, nullptr, enclosingMask, enclosingMaskRect, referenceDevice, colorPolicy);
580 HardSelectionPolicy<TransparentForHalosDifferencePolicy> transparentPolicy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold());
581 selectRegionsFilledWithSpecificColorGeneric(resultMaskTransparent, nullptr, enclosingMask, enclosingMaskRect, referenceDevice, transparentPolicy);
582 }
583 // Compose the masks
584 resultMask->applySelection(resultMaskTransparent, SELECTION_ADD);
585 if (resultMaskRect) {
586 *resultMaskRect = resultMask->selectedExactRect();
587 }
588}
589
590template <typename SelectionPolicy>
592 QRect *resultMaskRect,
593 KisPixelSelectionSP enclosingMask,
594 const QRect &enclosingMaskRect,
595 KisPaintDeviceSP referenceDevice,
596 SelectionPolicy selectionPolicy) const
597{
598 // Select all the pixels using the given selection policy and
599 // return if there are no selected pixels
600 if (selectSimilarRegions(resultMask, enclosingMask, enclosingMaskRect, referenceDevice, selectionPolicy) == 0) {
601 if (resultMaskRect) {
602 *resultMaskRect = QRect();
603 }
604 return;
605 }
606 // Remove the regions that touch the enclosing area
608 removeContourRegions(resultMask, enclosingMask, enclosingMaskRect, referenceDevice);
609 }
610 if (resultMaskRect) {
611 *resultMaskRect = resultMask->selectedExactRect();
612 }
613}
614
616 QRect *resultMaskRect,
617 KisPixelSelectionSP enclosingMask,
618 const QRect &enclosingMaskRect,
619 KisPaintDeviceSP referenceDevice) const
620{
621 using namespace KisEncloseAndFillPainterDetail;
622 const int softness = 100 - q->opacitySpread();
623 if (softness == 0) {
624 HardSelectionPolicy<SpecificColorDifferencePolicy> policy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold());
625 selectAllRegionsExceptFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
626 } else {
627 SoftSelectionPolicy<SpecificColorDifferencePolicy> policy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold(), softness);
628 selectAllRegionsExceptFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
629 }
630}
631
633 QRect *resultMaskRect,
634 KisPixelSelectionSP enclosingMask,
635 const QRect &enclosingMaskRect,
636 KisPaintDeviceSP referenceDevice) const
637{
638 using namespace KisEncloseAndFillPainterDetail;
639 const int softness = 100 - q->opacitySpread();
640 if (softness == 0) {
641 HardSelectionPolicy<TransparentDifferencePolicy> policy(referenceDevice->colorSpace(), KoColor::createTransparent(referenceDevice->colorSpace()), q->fillThreshold());
642 selectAllRegionsExceptFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
643 } else {
644 SoftSelectionPolicy<TransparentDifferencePolicy> policy(referenceDevice->colorSpace(), KoColor::createTransparent(referenceDevice->colorSpace()), q->fillThreshold(), softness);
645 selectAllRegionsExceptFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
646 }
647}
648
650 QRect *resultMaskRect,
651 KisPixelSelectionSP enclosingMask,
652 const QRect &enclosingMaskRect,
653 KisPaintDeviceSP referenceDevice) const
654{
655 using namespace KisEncloseAndFillPainterDetail;
656 const int softness = 100 - q->opacitySpread();
657 // Here we must compute the specific color and transparent masks separately
658 if (softness == 0) {
660 selectAllRegionsExceptFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
661 } else {
662 SoftSelectionPolicy<SpecificColorOrTransparentDifferencePolicy> policy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold(), softness);
663 selectAllRegionsExceptFilledWithSpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
664 }
665}
666
667template <typename SelectionPolicy>
669 QRect *resultMaskRect,
670 KisPixelSelectionSP enclosingMask,
671 const QRect &enclosingMaskRect,
672 KisPaintDeviceSP referenceDevice,
673 SelectionPolicy selectionPolicy) const
674{
675 const QVector<QPoint> enclosingPoints = getEnclosingContourPoints(enclosingMask, enclosingMaskRect);
676 // Remove the regions that touch the enclosing area
677 if (selectDissimilarRegions(resultMask, enclosingMask, enclosingMaskRect, referenceDevice, selectionPolicy) == 0) {
678 if (resultMaskRect) {
679 *resultMaskRect = QRect();
680 }
681 return;
682 }
684 // Here we don't use removeContourRegions because the contour regions
685 // in the mask may include multiple connected color regions
687 selectRegionsFromContour(mask, enclosingMask, enclosingPoints, enclosingMaskRect, referenceDevice);
688 resultMask->applySelection(mask, SELECTION_SUBTRACT);
689 }
690 if (resultMaskRect) {
691 *resultMaskRect = resultMask->selectedExactRect();
692 }
693}
694
696 QRect *resultMaskRect,
697 KisPixelSelectionSP enclosingMask,
698 const QRect &enclosingMaskRect,
699 KisPaintDeviceSP referenceDevice) const
700{
701 using namespace KisEncloseAndFillPainterDetail;
702 const int softness = 100 - q->opacitySpread();
703 if (softness == 0) {
704 HardSelectionPolicy<SpecificColorDifferencePolicy> policy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold());
705 selectRegionsSurroundedBySpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
706 } else {
707 SoftSelectionPolicy<SpecificColorDifferencePolicy> policy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold(), softness);
708 selectRegionsSurroundedBySpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
709 }
710}
711
713 QRect *resultMaskRect,
714 KisPixelSelectionSP enclosingMask,
715 const QRect &enclosingMaskRect,
716 KisPaintDeviceSP referenceDevice) const
717{
718 using namespace KisEncloseAndFillPainterDetail;
719 const int softness = 100 - q->opacitySpread();
720 if (softness == 0) {
721 HardSelectionPolicy<TransparentDifferencePolicy> policy(referenceDevice->colorSpace(), KoColor::createTransparent(referenceDevice->colorSpace()), q->fillThreshold());
722 selectRegionsSurroundedBySpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
723 } else {
724 SoftSelectionPolicy<TransparentDifferencePolicy> policy(referenceDevice->colorSpace(), KoColor::createTransparent(referenceDevice->colorSpace()), q->fillThreshold(), softness);
725 selectRegionsSurroundedBySpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, policy);
726 }
727}
728
730 QRect *resultMaskRect,
731 KisPixelSelectionSP enclosingMask,
732 const QRect &enclosingMaskRect,
733 KisPaintDeviceSP referenceDevice) const
734{
735 using namespace KisEncloseAndFillPainterDetail;
736 const int softness = 100 - q->opacitySpread();
737 // Here we must compute the specific color and transparent masks separately
738 KisPixelSelectionSP resultMaskTransparent = new KisPixelSelection(new KisSelectionDefaultBounds(resultMask));
739 if (softness == 0) {
741 selectRegionsSurroundedBySpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, colorPolicy, true);
742 } else {
743 SoftSelectionPolicy<SpecificColorOrTransparentDifferencePolicy> colorPolicy(referenceDevice->colorSpace(), regionSelectionColor, q->fillThreshold(), softness);
744 selectRegionsSurroundedBySpecificColorGeneric(resultMask, resultMaskRect, enclosingMask, enclosingMaskRect, referenceDevice, colorPolicy, true);
745 }
746}
747
748template <typename SelectionPolicy>
750 QRect *resultMaskRect,
751 KisPixelSelectionSP enclosingMask,
752 const QRect &enclosingMaskRect,
753 KisPaintDeviceSP referenceDevice,
754 SelectionPolicy selectionPolicy,
755 bool colorOrTransparent) const
756{
757 // Get the enclosing mask contour points
758 const QVector<QPoint> enclosingPoints = getEnclosingContourPoints(enclosingMask, enclosingMaskRect);
759 if (enclosingPoints.isEmpty()) {
760 return;
761 }
762 // Here we just fill all the areas from the border towards inside until the
763 // specific color. This selects any region that touches the enclosing area
764 // contour and that is not equal to the surrounding color
765 if (colorOrTransparent) {
766 selectRegionsFromContourUntilColorOrTransparent(resultMask, enclosingMask, enclosingPoints, enclosingMaskRect, referenceDevice, selectionPolicy.color);
767 } else {
768 selectRegionsFromContourUntilColor(resultMask, enclosingMask, enclosingPoints, enclosingMaskRect, referenceDevice, selectionPolicy.color);
769 }
770 // Invert the mask since it contains the regions surrounding the regions we
771 // want, that is, the regions that touch the enclosing area contour and that
772 // are not equal to the surrounding color. We want the opposite
773 invertMaskRect(resultMask, enclosingMaskRect);
774 // Since, after inverting, the mask includes the region outside the enclosing
775 // mask, we must intersect the current mask with the enclosing mask. The result
776 // is a mask that includes all the closed regions inside the enclosing mask
777 resultMask->applySelection(enclosingMask, SELECTION_INTERSECT);
778
780 // Remove the regions that touch the enclosing area
781 removeContourRegions(resultMask, enclosingMask, enclosingPoints, enclosingMaskRect, referenceDevice);
782 } else {
783 // Remove the surrounding regions. Also there shouldn't be any regions
784 // that touch the enclosing area contour after this step
786 selectSimilarRegions(mask, enclosingMask, enclosingMaskRect, referenceDevice, selectionPolicy);
787 resultMask->applySelection(mask, SELECTION_SUBTRACT);
788 }
789 if (resultMaskRect) {
790 *resultMaskRect = resultMask->selectedExactRect();
791 }
792}
793
795 const QRect &enclosingMaskRect) const
796{
797 QVector<QPoint> enclosingPoints;
798 const int scanlineWidth = enclosingMaskRect.width() + 2;
799 QVector<quint8> buffer(scanlineWidth * 3);
800 quint8 *scanlines[3] = {buffer.data(), buffer.data() + scanlineWidth, buffer.data() + scanlineWidth * 2};
801 // Initialize the buffer
802 // Top, outside row
803 memset(scanlines[0], MIN_SELECTED, scanlineWidth);
804 // Middle row
805 // Left, outside pixel
806 *(scanlines[1]) = MIN_SELECTED;
807 // Middle, inside pixels
808 enclosingMask->readBytes(scanlines[1] + 1, enclosingMaskRect.x(), enclosingMaskRect.y(), enclosingMaskRect.width(), 1);
809 // Right, outside pixel
810 *(scanlines[2] - 1) = MIN_SELECTED;
811 // Bottom row
812 if (enclosingMaskRect.height() == 1) {
813 // Bottom, outside row
814 memset(scanlines[2], MIN_SELECTED, scanlineWidth);
815 } else {
816 // Left, outside pixel
817 *(scanlines[2]) = MIN_SELECTED;
818 // Middle, inside pixels
819 enclosingMask->readBytes(scanlines[2] + 1, enclosingMaskRect.x(), enclosingMaskRect.y() + 1, enclosingMaskRect.width(), 1);
820 // Right, outside pixel
821 *(scanlines[2] + scanlineWidth - 1) = MIN_SELECTED;
822 }
823
824 for (int y = 0; y < enclosingMaskRect.height(); ++y) {
825 if (y > 0) {
826 // Rotate pointers
827 quint8 *tmp = scanlines[0];
828 scanlines[0] = scanlines[1];
829 scanlines[1] = scanlines[2];
830 scanlines[2] = tmp;
831 // Read new row
832 if (y == enclosingMaskRect.height() - 1) {
833 // Bottom, outside row
834 memset(scanlines[2], MIN_SELECTED, scanlineWidth);
835 } else {
836 // Left, outside pixel
837 *(scanlines[2]) = MIN_SELECTED;
838 // Middle, inside pixels
839 enclosingMask->readBytes(scanlines[2] + 1, enclosingMaskRect.x(), enclosingMaskRect.y() + y + 1, enclosingMaskRect.width(), 1);
840 // Right, outside pixel
841 *(scanlines[2] + scanlineWidth - 1) = MIN_SELECTED;
842 }
843 }
844 const quint8 *topPixel = scanlines[0] + 1;
845 const quint8 *middlePixel = scanlines[1] + 1;
846 const quint8 *bottomPixel = scanlines[2] + 1;
847 for (int x = 0; x < enclosingMaskRect.width(); ++x, ++topPixel, ++middlePixel, ++bottomPixel) {
848 // Continue if the current pixel is not in the selection
849 if (*middlePixel == MIN_SELECTED) {
850 continue;
851 }
852 // Get all eight neighbor pixels. If at least one of them is not
853 // in the selection then the current pixel is a border pixel and
854 // we add it to the list
855 quint8 neighbors = 0;
856 neighbors |= (*(topPixel - 1) == MIN_SELECTED) << 7;
857 neighbors |= (*(topPixel ) == MIN_SELECTED) << 6;
858 neighbors |= (*(topPixel + 1) == MIN_SELECTED) << 5;
859 neighbors |= (*(middlePixel - 1) == MIN_SELECTED) << 4;
860 neighbors |= (*(middlePixel + 1) == MIN_SELECTED) << 3;
861 neighbors |= (*(bottomPixel - 1) == MIN_SELECTED) << 2;
862 neighbors |= (*(bottomPixel ) == MIN_SELECTED) << 1;
863 neighbors |= (*(bottomPixel + 1) == MIN_SELECTED) << 0;
864 if (neighbors != 0) {
865 enclosingPoints.push_back(QPoint(enclosingMaskRect.x() + x, enclosingMaskRect.y() + y));
866 }
867 }
868 }
869
870 return enclosingPoints;
871}
872
874 KisPaintDeviceSP referenceDevice) const
875{
876 if (q->sizemod() > 0) {
877 if (q->stopGrowingAtDarkestPixel()) {
878 KisGrowUntilDarkestPixelSelectionFilter biggy(q->sizemod(), referenceDevice);
879 biggy.process(
880 mask,
881 mask->selectedRect().adjusted(
882 -q->sizemod(), -q->sizemod(), q->sizemod(), q->sizemod()
883 )
884 );
885 } else {
886 KisGrowSelectionFilter biggy(q->sizemod(), q->sizemod());
887 biggy.process(
888 mask,
889 mask->selectedRect().adjusted(
890 -q->sizemod(), -q->sizemod(), q->sizemod(), q->sizemod()
891 )
892 );
893 }
894 } else if (q->sizemod() < 0) {
895 KisShrinkSelectionFilter tiny(-q->sizemod(), -q->sizemod(), false);
896 tiny.process(mask, mask->selectedRect());
897 }
898 // Since the feathering already smooths the selection, the antiAlias
899 // is not applied if we must feather
900 if (q->feather() > 0) {
901 KisFeatherSelectionFilter feathery(q->feather());
902 feathery.process(mask, mask->selectedRect().adjusted(-q->feather(), -q->feather(), q->feather(), q->feather()));
903 } else if (q->antiAlias()) {
904 KisAntiAliasSelectionFilter antiAliasFilter;
905 antiAliasFilter.process(mask, mask->selectedRect());
906 }
907}
908
909void KisEncloseAndFillPainter::Private::invertIfNeeded(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect) const
910{
912 return;
913 }
914 invertMaskRect(resultMask, enclosingMaskRect);
915 // Since, after inverting, the mask includes the region outside the enclosing
916 // mask, we must intersect the current mask with the enclosing mask. The result
917 // is a mask that includes all the closed regions inside the enclosing mask
918 resultMask->applySelection(enclosingMask, SELECTION_INTERSECT);
919}
920
921template <typename SelectionPolicy>
923 KisPixelSelectionSP enclosingMask,
924 const QRect &enclosingMaskRect,
925 KisPaintDeviceSP referenceDevice,
926 SelectionPolicy selectionPolicy) const
927{
928 KisSequentialIterator resultMaskIterator(resultMask, enclosingMaskRect);
929 KisSequentialConstIterator enclosingMaskIterator(enclosingMask, enclosingMaskRect);
930 KisSequentialConstIterator referenceDeviceIterator(referenceDevice, enclosingMaskRect);
931 int nPixels = 0;
932 // Select all the pixels using the given selection policy
933 while (resultMaskIterator.nextPixel() && enclosingMaskIterator.nextPixel() && referenceDeviceIterator.nextPixel()) {
934 if (*enclosingMaskIterator.oldRawData() == MIN_SELECTED) {
935 continue;
936 }
937 const quint8 selection = selectionPolicy.getSelectionFor(referenceDeviceIterator.oldRawData());
938 if (selection > MIN_SELECTED) {
939 *resultMaskIterator.rawData() = selection;
940 ++nPixels;
941 }
942 }
943 return nPixels;
944}
945
946template <typename SelectionPolicy>
948 KisPixelSelectionSP enclosingMask,
949 const QRect &enclosingMaskRect,
950 KisPaintDeviceSP referenceDevice,
951 SelectionPolicy selectionPolicy) const
952{
953 KisSequentialIterator resultMaskIterator(resultMask, enclosingMaskRect);
954 KisSequentialConstIterator enclosingMaskIterator(enclosingMask, enclosingMaskRect);
955 KisSequentialConstIterator referenceDeviceIterator(referenceDevice, enclosingMaskRect);
956 int nPixels = 0;
957 // Select all the pixels using the given selection policy
958 while (resultMaskIterator.nextPixel() && enclosingMaskIterator.nextPixel() && referenceDeviceIterator.nextPixel()) {
959 if (*enclosingMaskIterator.oldRawData() == MIN_SELECTED) {
960 continue;
961 }
962 const quint8 selection = MAX_SELECTED - selectionPolicy.getSelectionFor(referenceDeviceIterator.oldRawData());
963 if (selection > MIN_SELECTED) {
964 *resultMaskIterator.rawData() = selection;
965 ++nPixels;
966 }
967 }
968 return nPixels;
969}
970
972 KisPixelSelectionSP enclosingMask,
973 const QRect &enclosingMaskRect,
974 KisPaintDeviceSP referenceDevice) const
975{
976 const QVector<QPoint> enclosingPoints = getEnclosingContourPoints(enclosingMask, enclosingMaskRect);
977 selectRegionsFromContour(resultMask, enclosingMask, enclosingPoints, enclosingMaskRect, referenceDevice);
978}
979
981 KisPixelSelectionSP enclosingMask,
982 const QVector<QPoint> &enclosingPoints,
983 const QRect &enclosingMaskRect,
984 KisPaintDeviceSP referenceDevice) const
985{
986 if (enclosingPoints.isEmpty()) {
987 return;
988 }
989 const QRect inclusionRect = q->device()->defaultBounds()->wrapAroundMode()
990 ? enclosingMaskRect
991 : imageRect;
992 // Here we just fill all the areas from the border towards inside
993 for (const QPoint &point : enclosingPoints) {
994 if (!inclusionRect.contains(point)) {
995 continue;
996 }
997 // Continue if the region under the point was already filled
998 if (*(resultMask->pixel(point).data()) == MAX_SELECTED) {
999 continue;
1000 }
1002 KisScanlineFill gc(referenceDevice, point, inclusionRect);
1003 gc.setThreshold(q->fillThreshold());
1004 gc.setOpacitySpread(q->opacitySpread());
1005 gc.setCloseGap(q->closeGap());
1006 // Use the enclosing mask as boundary so that we don't fill
1007 // potentially large regions on the outside
1008 gc.fillSelection(mask, enclosingMask);
1009 resultMask->applySelection(mask, SELECTION_ADD);
1010 }
1011}
1012
1014 KisPixelSelectionSP enclosingMask,
1015 const QRect &enclosingMaskRect,
1016 KisPaintDeviceSP referenceDevice,
1017 const KoColor &color) const
1018{
1019 const QVector<QPoint> enclosingPoints = getEnclosingContourPoints(enclosingMask, enclosingMaskRect);
1020 selectRegionsFromContourUntilColor(resultMask, enclosingMask, enclosingPoints, enclosingMaskRect, referenceDevice, color);
1021}
1022
1024 KisPixelSelectionSP enclosingMask,
1025 const QVector<QPoint> &enclosingPoints,
1026 const QRect &enclosingMaskRect,
1027 KisPaintDeviceSP referenceDevice,
1028 const KoColor &color) const
1029{
1030 if (enclosingPoints.isEmpty()) {
1031 return;
1032 }
1033 const QRect inclusionRect = q->device()->defaultBounds()->wrapAroundMode()
1034 ? enclosingMaskRect
1035 : imageRect;
1036 // Here we just fill all the areas from the border towards inside until the specific color
1037 for (const QPoint &point : enclosingPoints) {
1038 if (!inclusionRect.contains(point)) {
1039 continue;
1040 }
1041 // Continue if the region under the point was already filled
1042 if (*(resultMask->pixel(point).data()) == MAX_SELECTED) {
1043 continue;
1044 }
1046 KisScanlineFill gc(referenceDevice, point, inclusionRect);
1047 gc.setThreshold(q->fillThreshold());
1048 gc.setOpacitySpread(q->opacitySpread());
1049 gc.setCloseGap(q->closeGap());
1050 // Use the enclosing mask as boundary so that we don't fill
1051 // potentially large regions in the outside
1052 gc.fillSelectionUntilColor(mask, color, enclosingMask);
1053 resultMask->applySelection(mask, SELECTION_ADD);
1054 }
1055}
1056
1058 KisPixelSelectionSP enclosingMask,
1059 const QRect &enclosingMaskRect,
1060 KisPaintDeviceSP referenceDevice,
1061 const KoColor &color) const
1062{
1063 const QVector<QPoint> enclosingPoints = getEnclosingContourPoints(enclosingMask, enclosingMaskRect);
1064 selectRegionsFromContourUntilColorOrTransparent(resultMask, enclosingMask, enclosingPoints, enclosingMaskRect, referenceDevice, color);
1065}
1066
1068 KisPixelSelectionSP enclosingMask,
1069 const QVector<QPoint> &enclosingPoints,
1070 const QRect &enclosingMaskRect,
1071 KisPaintDeviceSP referenceDevice,
1072 const KoColor &color) const
1073{
1074 if (enclosingPoints.isEmpty()) {
1075 return;
1076 }
1077 const QRect inclusionRect = q->device()->defaultBounds()->wrapAroundMode()
1078 ? enclosingMaskRect
1079 : imageRect;
1080 // Here we just fill all the areas from the border towards inside until the specific color
1081 for (const QPoint &point : enclosingPoints) {
1082 if (!inclusionRect.contains(point)) {
1083 continue;
1084 }
1085 // Continue if the region under the point was already filled
1086 if (*(resultMask->pixel(point).data()) == MAX_SELECTED) {
1087 continue;
1088 }
1090 KisScanlineFill gc(referenceDevice, point, inclusionRect);
1091 gc.setThreshold(q->fillThreshold());
1092 gc.setOpacitySpread(q->opacitySpread());
1093 gc.setCloseGap(q->closeGap());
1094 // Use the enclosing mask as boundary so that we don't fill
1095 // potentially large regions in the outside
1096 gc.fillSelectionUntilColorOrTransparent(mask, color, enclosingMask);
1097 resultMask->applySelection(mask, SELECTION_ADD);
1098 }
1099}
1100
1102 KisPixelSelectionSP enclosingMask,
1103 const QRect &enclosingMaskRect,
1104 KisPaintDeviceSP referenceDevice) const
1105{
1106 const QVector<QPoint> enclosingPoints = getEnclosingContourPoints(enclosingMask, enclosingMaskRect);
1107 removeContourRegions(resultMask, enclosingMask, enclosingPoints, enclosingMaskRect, referenceDevice);
1108}
1109
1111 KisPixelSelectionSP enclosingMask,
1112 const QVector<QPoint> &enclosingPoints,
1113 const QRect &enclosingMaskRect,
1114 KisPaintDeviceSP referenceDevice) const
1115{
1116 if (enclosingPoints.isEmpty()) {
1117 return;
1118 }
1119
1120 KisPixelSelectionSP contourRegionsMask = new KisPixelSelection(new KisSelectionDefaultBounds(enclosingMask));
1121 selectRegionsFromContour(contourRegionsMask, enclosingMask, enclosingMaskRect, referenceDevice);
1122 resultMask->applySelection(contourRegionsMask, SELECTION_SUBTRACT);
1123}
1124
1126{
1127 KisSequentialIterator resultMaskIterator(resultMask, rect);
1128 while (resultMaskIterator.nextPixel()) {
1129 *resultMaskIterator.rawData() = MAX_SELECTED - *resultMaskIterator.oldRawData();
1130 }
1131}
qreal v
@ SELECTION_REPLACE
@ SELECTION_INTERSECT
@ SELECTION_SUBTRACT
@ SELECTION_ADD
AntiAlias filter for selections inspired by FXAA.
void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override
virtual bool wrapAroundMode() const =0
int selectSimilarRegions(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice, SelectionPolicy selectionPolicy) const
void selectRegionsFilledWithTransparent(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
int selectDissimilarRegions(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice, SelectionPolicy selectionPolicy) const
void removeContourRegions(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void applyPostProcessing(KisPixelSelectionSP mask, KisPaintDeviceSP referenceDevice) const
void selectRegionsFilledWithSpecificColorOrTransparent(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void selectRegionsFromContourUntilColor(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice, const KoColor &color) const
void selectRegionsSurroundedByTransparent(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void selectAllRegionsExceptFilledWithSpecificColorGeneric(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice, SelectionPolicy selectionPolicy) const
void invertMaskRect(KisPixelSelectionSP resultMask, const QRect &rect) const
QVector< QPoint > getEnclosingContourPoints(KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect) const
void selectRegionsFromContour(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void selectAllRegionsExceptFilledWithSpecificColorOrTransparent(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void selectRegionsSurroundedBySpecificColor(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void selectRegionsFilledWithSpecificColorGeneric(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice, SelectionPolicy selectionPolicy) const
void selectRegionsFilledWithSpecificColor(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void selectAllRegionsExceptFilledWithSpecificColor(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void computeEnclosedRegionsMask(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void selectRegionsSurroundedBySpecificColorGeneric(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice, SelectionPolicy selectionPolicy, bool colorOrTransparent=false) const
void selectRegionsFromContourUntilColorOrTransparent(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice, const KoColor &color) const
void invertIfNeeded(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect) const
void selectAllRegionsExceptFilledWithTransparent(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void selectRegionsSurroundedBySpecificColorOrTransparent(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
void selectAllRegions(KisPixelSelectionSP resultMask, QRect *resultMaskRect, KisPixelSelectionSP enclosingMask, const QRect &enclosingMaskRect, KisPaintDeviceSP referenceDevice) const
KisEncloseAndFillPainter(const QSize &imageSize)
void setRegionSelectionIncludeContourRegions(bool include)
void setRegionSelectionIncludeSurroundingRegions(bool include)
void setRegionSelectionColor(const KoColor &color)
void encloseAndFillPattern(KisPixelSelectionSP enclosingMask, KisPaintDeviceSP referenceDevice, QTransform patternTransform=QTransform())
KisPixelSelectionSP createEncloseAndFillSelection(KisPixelSelectionSP enclosingMask, KisPaintDeviceSP referenceDevice, KisPixelSelectionSP existingSelection)
void encloseAndFillColor(KisPixelSelectionSP enclosingMask, KisPaintDeviceSP referenceDevice)
RegionSelectionMethod regionSelectionMethod() const
void genericEncloseAndFillEnd(KisPaintDeviceSP filled)
void setRegionSelectionMethod(RegionSelectionMethod regionSelectionMethod)
QScopedPointer< Private > m_d
void genericEncloseAndFillStart(KisPixelSelectionSP enclosingMask, KisPaintDeviceSP referenceDevice)
void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override
void setWidth(int w)
void setHeight(int h)
KisSelectionSP currentFillSelection() const
void fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor &c, quint8 opacity)
uint useSelectionAsBoundary() const
void setCurrentFillSelection(KisSelectionSP fillSelection)
void genericFillEnd(KisPaintDeviceSP filled)
void fillRectNoCompose(const QRect &rc, const KoPatternSP pattern, const QTransform transform)
fillRect Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the enti...
void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override
Filter that dilates a selection and that can stop dilating adaptively at areas of higher darkness or ...
void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override
static KisImageResolutionProxySP identity()
KisPaintDeviceSP createCompositionSourceDevice() const
const KoColorSpace * colorSpace() const
bool pixel(qint32 x, qint32 y, QColor *c) const
KisDefaultBoundsBaseSP defaultBounds() const
void readBytes(quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h) const
KisPainter * q
KoColor paintColor
KisSelectionSP selection
QTransform patternTransform
KisPaintDeviceSP device
KoPatternSP pattern
ALWAYS_INLINE quint8 * rawData()
ALWAYS_INLINE const quint8 * oldRawData() const
void process(KisPixelSelectionSP pixelSelection, const QRect &rect) override
virtual quint8 difference(const quint8 *src1, const quint8 *src2) const =0
virtual quint8 differenceA(const quint8 *src1, const quint8 *src2) const =0
virtual quint8 opacityU8(const quint8 *pixel) const =0
static KoColor createTransparent(const KoColorSpace *cs)
Definition KoColor.cpp:681
quint8 * data()
Definition KoColor.h:144
const quint8 MAX_SELECTED
Definition kis_global.h:32
const quint8 quint8_MAX
Definition kis_global.h:24
const quint8 MIN_SELECTED
Definition kis_global.h:33
HardSelectionPolicy(const KoColorSpace *colorSpace, const KoColor &color, int threshold)
SoftSelectionPolicy(const KoColorSpace *colorSpace, const KoColor &color, int threshold, int softness)
SpecificColorDifferencePolicy(const KoColorSpace *colorSpace, const KoColor &color)
SpecificColorOrTransparentDifferencePolicy(const KoColorSpace *colorSpace, const KoColor &color)
TransparentDifferencePolicy(const KoColorSpace *colorSpace, const KoColor &color)
TransparentForHalosDifferencePolicy(const KoColorSpace *colorSpace, const KoColor &color)
QRect selectedExactRect() const
void applySelection(KisPixelSelectionSP selection, SelectionAction action)
void fillSelectionUntilColor(KisPixelSelectionSP pixelSelection, const KoColor &boundaryColor, KisPaintDeviceSP boundarySelection)
void setCloseGap(int closeGap)
void fillSelection(KisPixelSelectionSP pixelSelection, KisPaintDeviceSP boundarySelection)
void fillSelectionUntilColorOrTransparent(KisPixelSelectionSP pixelSelection, const KoColor &boundaryColor, KisPaintDeviceSP boundarySelection)
void setThreshold(int threshold)
void setOpacitySpread(int opacitySpread)
KisPixelSelectionSP pixelSelection
QRect selectedExactRect() const
Slow, but exact way of determining the rectangle that encloses the selection.