Commit 60b0d351 authored by Deif Lou's avatar Deif Lou
Browse files

Make the enclose and fill tool take into account canvas limits.

Now, when the wrap around mode is not active, the canvas border is taken as
another limit when finding the regions

BUG:456299
parent 8640cf1d
Pipeline #201139 canceled with stage
......@@ -130,6 +130,7 @@ public:
bool regionSelectionInvert {false};
bool regionSelectionIncludeContourRegions {true};
bool regionSelectionIncludeSurroundingRegions {true};
QRect imageRect;
Private(KisEncloseAndFillPainter *q) : q(q) {}
......@@ -281,19 +282,31 @@ public:
const QRect &rect) const;
};
KisEncloseAndFillPainter::KisEncloseAndFillPainter()
KisEncloseAndFillPainter::KisEncloseAndFillPainter(const QSize &imageSize)
: m_d(new Private(this))
{}
{
setWidth(imageSize.width());
setHeight(imageSize.height());
m_d->imageRect = QRect(QPoint(0, 0), imageSize);
}
KisEncloseAndFillPainter::KisEncloseAndFillPainter(KisPaintDeviceSP device)
KisEncloseAndFillPainter::KisEncloseAndFillPainter(KisPaintDeviceSP device, const QSize &imageSize)
: KisFillPainter(device)
, m_d(new Private(this))
{}
{
setWidth(imageSize.width());
setHeight(imageSize.height());
m_d->imageRect = QRect(QPoint(0, 0), imageSize);
}
KisEncloseAndFillPainter::KisEncloseAndFillPainter(KisPaintDeviceSP device, KisSelectionSP selection)
KisEncloseAndFillPainter::KisEncloseAndFillPainter(KisPaintDeviceSP device, KisSelectionSP selection, const QSize &imageSize)
: KisFillPainter(device, selection)
, m_d(new Private(this))
{}
{
setWidth(imageSize.width());
setHeight(imageSize.height());
m_d->imageRect = QRect(QPoint(0, 0), imageSize);
}
KisEncloseAndFillPainter::~KisEncloseAndFillPainter()
{}
......@@ -482,9 +495,10 @@ void KisEncloseAndFillPainter::Private::selectAllRegions(KisPixelSelectionSP res
const QRect &enclosingMaskRect,
KisPaintDeviceSP referenceDevice) const
{
// For performance reasons, this function outputs an inverted version of the enclosed regions
// Here we just fill all the connected regions from the border towards inside
selectRegionsFromContour(resultMask, enclosingMask, enclosingMaskRect, referenceDevice);
resultMask->applySelection(enclosingMask, SELECTION_REPLACE);
KisPixelSelectionSP mask = new KisPixelSelection(new KisSelectionDefaultBounds(enclosingMask));
selectRegionsFromContour(mask, enclosingMask, enclosingMaskRect, referenceDevice);
resultMask->applySelection(mask, SELECTION_SUBTRACT);
if (resultMaskRect) {
*resultMaskRect = resultMask->selectedExactRect();
}
......@@ -859,12 +873,7 @@ void KisEncloseAndFillPainter::Private::applyPostProcessing(KisPixelSelectionSP
void KisEncloseAndFillPainter::Private::invertIfNeeded(KisPixelSelectionSP resultMask, KisPixelSelectionSP enclosingMask) const
{
if (regionSelectionMethod == SelectAllRegions) {
// Return if the mask should be inverted since here it is already inverted
if (regionSelectionInvert) {
return;
}
} else if (!regionSelectionInvert) {
if (!regionSelectionInvert) {
return;
}
resultMask->invert();
......@@ -942,14 +951,20 @@ void KisEncloseAndFillPainter::Private::selectRegionsFromContour(KisPixelSelecti
if (enclosingPoints.isEmpty()) {
return;
}
const QRect inclusionRect = q->device()->defaultBounds()->wrapAroundMode()
? enclosingMaskRect
: imageRect;
// Here we just fill all the areas from the border towards inside
for (const QPoint &point : enclosingPoints) {
if (!inclusionRect.contains(point)) {
continue;
}
// Continue if the region under the point was already filled
if (*(resultMask->pixel(point).data()) == MAX_SELECTED) {
continue;
}
KisPixelSelectionSP mask = new KisPixelSelection(new KisSelectionDefaultBounds(resultMask));
KisScanlineFill gc(referenceDevice, point, enclosingMaskRect);
KisScanlineFill gc(referenceDevice, point, inclusionRect);
gc.setThreshold(q->fillThreshold());
gc.setOpacitySpread(q->opacitySpread());
// Use the enclosing mask as boundary so that we don't fill
......@@ -979,14 +994,20 @@ void KisEncloseAndFillPainter::Private::selectRegionsFromContourUntilColor(KisPi
if (enclosingPoints.isEmpty()) {
return;
}
const QRect inclusionRect = q->device()->defaultBounds()->wrapAroundMode()
? enclosingMaskRect
: imageRect;
// Here we just fill all the areas from the border towards inside until the specific color
for (const QPoint &point : enclosingPoints) {
if (!inclusionRect.contains(point)) {
continue;
}
// Continue if the region under the point was already filled
if (*(resultMask->pixel(point).data()) == MAX_SELECTED) {
continue;
}
KisPixelSelectionSP mask = new KisPixelSelection(new KisSelectionDefaultBounds(resultMask));
KisScanlineFill gc(referenceDevice, point, enclosingMaskRect);
KisScanlineFill gc(referenceDevice, point, inclusionRect);
gc.setThreshold(q->fillThreshold());
gc.setOpacitySpread(q->opacitySpread());
// Use the enclosing mask as boundary so that we don't fill
......@@ -1016,14 +1037,20 @@ void KisEncloseAndFillPainter::Private::selectRegionsFromContourUntilColorOrTran
if (enclosingPoints.isEmpty()) {
return;
}
const QRect inclusionRect = q->device()->defaultBounds()->wrapAroundMode()
? enclosingMaskRect
: imageRect;
// Here we just fill all the areas from the border towards inside until the specific color
for (const QPoint &point : enclosingPoints) {
if (!inclusionRect.contains(point)) {
continue;
}
// Continue if the region under the point was already filled
if (*(resultMask->pixel(point).data()) == MAX_SELECTED) {
continue;
}
KisPixelSelectionSP mask = new KisPixelSelection(new KisSelectionDefaultBounds(resultMask));
KisScanlineFill gc(referenceDevice, point, enclosingMaskRect);
KisScanlineFill gc(referenceDevice, point, inclusionRect);
gc.setThreshold(q->fillThreshold());
gc.setOpacitySpread(q->opacitySpread());
// Use the enclosing mask as boundary so that we don't fill
......@@ -1048,13 +1075,19 @@ void KisEncloseAndFillPainter::Private::removeContourRegions(KisPixelSelectionSP
if (enclosingPoints.isEmpty()) {
return;
}
const QRect inclusionRect = q->device()->defaultBounds()->wrapAroundMode()
? enclosingMaskRect
: imageRect;
// Here we just fill all the non-zero areas from the border towards inside
for (const QPoint &point : enclosingPoints) {
if (!inclusionRect.contains(point)) {
continue;
}
// Continue if the region under the point was already filled
if (*(resultMask->pixel(point).data()) == MIN_SELECTED) {
continue;
}
KisScanlineFill gc(resultMask, point, enclosingMaskRect);
KisScanlineFill gc(resultMask, point, inclusionRect);
gc.clearNonZeroComponent();
}
}
......@@ -87,13 +87,13 @@ public:
* Construct an empty painter. Use the begin(KisPaintDeviceSP) method to attach
* to a paint device
*/
KisEncloseAndFillPainter();
KisEncloseAndFillPainter(const QSize &imageSize);
/**
* Start painting on the specified paint device
*/
KisEncloseAndFillPainter(KisPaintDeviceSP device);
KisEncloseAndFillPainter(KisPaintDeviceSP device, const QSize &imageSize);
KisEncloseAndFillPainter(KisPaintDeviceSP device, KisSelectionSP selection);
KisEncloseAndFillPainter(KisPaintDeviceSP device, KisSelectionSP selection, const QSize &imageSize);
~KisEncloseAndFillPainter() override;
......
......@@ -73,7 +73,7 @@ void KisEncloseAndFillProcessingVisitor::fillPaintDevice(KisPaintDeviceSP device
const QRect fillRect = m_resources->image()->bounds();
KisEncloseAndFillPainter painter(device, m_selection);
KisEncloseAndFillPainter painter(device, m_selection, fillRect.size());
painter.beginTransaction();
m_resources->setupPainter(&painter);
......@@ -94,8 +94,6 @@ void KisEncloseAndFillProcessingVisitor::fillPaintDevice(KisPaintDeviceSP device
painter.setAntiAlias(m_antiAlias);
painter.setSizemod(m_expand);
painter.setFeather(m_feather);
painter.setWidth(fillRect.width());
painter.setHeight(fillRect.height());
KisPaintDeviceSP sourceDevice = m_unmerged ? device : m_referencePaintDevice;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment