Commit dfae2014 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement "Limit to layer bounds" feature of the Colorize Mask

If the outer color of the mask is transparent (e.g. when coloring
a character), the user might select "Limit to layer bounds" option,
which will limit the coloring area by the non-zero area of the parent
layer. It might speedup the coloring significantly.

CC:kimageshop@kde.org
parent 0c816c17
......@@ -65,7 +65,8 @@ struct KisColorizeMask::Private
dirtyParentUpdateCompressor(200, KisSignalCompressor::FIRST_ACTIVE_POSTPONE_NEXT, _q),
prefilterRecalculationCompressor(1000, KisSignalCompressor::POSTPONE, _q),
updateIsRunning(false),
filteringOptions(false, 4.0, 15, 0.7)
filteringOptions(false, 4.0, 15, 0.7),
limitToDeviceBounds(false)
{
}
......@@ -74,6 +75,7 @@ struct KisColorizeMask::Private
coloringProjection(new KisPaintDevice(*rhs.coloringProjection)),
fakePaintDevice(new KisPaintDevice(*rhs.fakePaintDevice)),
filteredSource(new KisPaintDevice(*rhs.filteredSource)),
filteredDeviceBounds(rhs.filteredDeviceBounds),
needAddCurrentKeyStroke(rhs.needAddCurrentKeyStroke),
showKeyStrokes(rhs.showKeyStrokes),
showColoring(rhs.showColoring),
......@@ -84,7 +86,8 @@ struct KisColorizeMask::Private
prefilterRecalculationCompressor(1000, KisSignalCompressor::POSTPONE, _q),
offset(rhs.offset),
updateIsRunning(false),
filteringOptions(rhs.filteringOptions)
filteringOptions(rhs.filteringOptions),
limitToDeviceBounds(rhs.limitToDeviceBounds)
{
Q_FOREACH (const KeyStroke &stroke, rhs.keyStrokes) {
keyStrokes << KeyStroke(KisPaintDeviceSP(new KisPaintDevice(*stroke.dev)), stroke.color, stroke.isTransparent);
......@@ -97,6 +100,7 @@ struct KisColorizeMask::Private
KisPaintDeviceSP coloringProjection;
KisPaintDeviceSP fakePaintDevice;
KisPaintDeviceSP filteredSource;
QRect filteredDeviceBounds;
KoColor currentColor;
KisPaintDeviceSP currentKeyStrokeDevice;
......@@ -122,6 +126,8 @@ struct KisColorizeMask::Private
FilteringOptions filteringOptions;
bool filteringDirty = true;
bool limitToDeviceBounds = false;
bool filteredSourceValid(KisPaintDeviceSP parentDevice) {
return !filteringDirty && originalSequenceNumber == parentDevice->sequenceNumber();
}
......@@ -130,7 +136,6 @@ struct KisColorizeMask::Private
bool shouldShowFilteredSource() const;
bool shouldShowColoring() const;
};
KisColorizeMask::KisColorizeMask()
......@@ -327,12 +332,26 @@ void KisColorizeMask::slotUpdateRegenerateFilling(bool prefilterOnly)
if (image) {
m_d->updateIsRunning = true;
QRect fillBounds;
if (m_d->limitToDeviceBounds) {
fillBounds |= src->exactBounds();
Q_FOREACH (const KeyStroke &stroke, m_d->keyStrokes) {
fillBounds |= stroke.dev->exactBounds();
}
fillBounds &= image->bounds();
} else {
fillBounds = image->bounds();
}
m_d->filteredDeviceBounds = fillBounds;
KisColorizeStrokeStrategy *strategy =
new KisColorizeStrokeStrategy(src,
m_d->coloringProjection,
m_d->filteredSource,
filteredSourceValid,
image->bounds(),
fillBounds,
this,
prefilterOnly);
......@@ -475,7 +494,6 @@ bool KisColorizeMask::Private::shouldShowColoring() const
coloringProjection;
}
QRect KisColorizeMask::decorateRect(KisPaintDeviceSP &src,
KisPaintDeviceSP &dst,
const QRect &rect,
......@@ -498,8 +516,10 @@ QRect KisColorizeMask::decorateRect(KisPaintDeviceSP &src,
KisPainter gc(dst);
if (m_d->shouldShowFilteredSource()) {
const QRect drawRect = rect & m_d->filteredDeviceBounds;
gc.setOpacity(128);
gc.bitBlt(rect.topLeft(), m_d->filteredSource, rect);
gc.bitBlt(drawRect.topLeft(), m_d->filteredSource, drawRect);
} else {
gc.setOpacity(255);
gc.bitBlt(rect.topLeft(), src, rect);
......@@ -1011,6 +1031,17 @@ qreal KisColorizeMask::cleanUpAmount() const
return m_d->filteringOptions.cleanUpAmount;
}
void KisColorizeMask::setLimitToDeviceBounds(bool value)
{
m_d->limitToDeviceBounds = value;
m_d->filteringDirty = true;
setNeedsUpdate(true);
}
bool KisColorizeMask::limitToDeviceBounds() const
{
return m_d->limitToDeviceBounds;
}
void KisColorizeMask::rerenderFakePaintDevice()
{
......
......@@ -114,6 +114,8 @@ public:
void setCleanUpAmount(qreal value);
qreal cleanUpAmount() const;
void setLimitToDeviceBounds(bool value);
bool limitToDeviceBounds() const;
void testingAddKeyStroke(KisPaintDeviceSP dev, const KoColor &color, bool isTransparent = false);
void testingRegenerateMask();
......
......@@ -41,7 +41,8 @@ public:
KisPaintDeviceSP dst,
KisPaintDeviceSP filteredSource,
bool filteredSourceValid,
const QRect &boundingRect, KisNodeSP progressNode,
const QRect &boundingRect,
KisNodeSP progressNode,
bool prefilterOnly = false);
KisColorizeStrokeStrategy(const KisColorizeStrokeStrategy &rhs, int levelOfDetail);
~KisColorizeStrokeStrategy() override;
......
......@@ -1039,11 +1039,13 @@ KisNodeSP KisKraLoader::loadColorizeMask(KisImageSP image, const KoXmlElement& e
const qreal edgeDetectionSize = KisDomUtils::toDouble(element.attribute(COLORIZE_EDGE_DETECTION_SIZE, "4"));
const qreal radius = KisDomUtils::toDouble(element.attribute(COLORIZE_FUZZY_RADIUS, "0"));
const int cleanUp = KisDomUtils::toInt(element.attribute(COLORIZE_CLEANUP, "0"));
const bool limitToDevice = KisDomUtils::toInt(element.attribute(COLORIZE_LIMIT_TO_DEVICE, "0"));
mask->setUseEdgeDetection(useEdgeDetection);
mask->setEdgeDetectionSize(edgeDetectionSize);
mask->setFuzzyRadius(radius);
mask->setCleanUpAmount(qreal(cleanUp) / 100.0);
mask->setLimitToDeviceBounds(limitToDevice);
delete mask->setColorSpace(colorSpace);
mask->setImage(image);
......
......@@ -424,6 +424,7 @@ void KisSaveXmlVisitor::saveMask(QDomElement & el, const QString & maskType, con
el.setAttribute(COLORIZE_EDGE_DETECTION_SIZE, KisDomUtils::toString(colorizeMask->edgeDetectionSize()));
el.setAttribute(COLORIZE_FUZZY_RADIUS, KisDomUtils::toString(colorizeMask->fuzzyRadius()));
el.setAttribute(COLORIZE_CLEANUP, int(100 * colorizeMask->cleanUpAmount()));
el.setAttribute(COLORIZE_LIMIT_TO_DEVICE, colorizeMask->limitToDeviceBounds());
}
}
......
......@@ -104,6 +104,7 @@ const QString COLORIZE_USE_EDGE_DETECTION = "use-edge-detection";
const QString COLORIZE_EDGE_DETECTION_SIZE = "edge-detection-size";
const QString COLORIZE_FUZZY_RADIUS = "fuzzy-radius";
const QString COLORIZE_CLEANUP = "cleanup";
const QString COLORIZE_LIMIT_TO_DEVICE = "limit-to-device";
const QString TRANSFORM_MASK = "transformmask";
const QString UUID = "uuid";
const QString VISIBLE = "visible";
......
......@@ -72,6 +72,7 @@ KisToolLazyBrushOptionsWidget::KisToolLazyBrushOptionsWidget(KisCanvasResourcePr
connect(m_d->ui->intEdgeDetectionSize, SIGNAL(valueChanged(int)), SLOT(slotEdgeDetectionSizeChanged(int)));
connect(m_d->ui->intRadius, SIGNAL(valueChanged(int)), SLOT(slotRadiusChanged(int)));
connect(m_d->ui->intCleanUp, SIGNAL(valueChanged(int)), SLOT(slotCleanUpChanged(int)));
connect(m_d->ui->chkLimitToDevice, SIGNAL(toggled(bool)), SLOT(slotLimitToDeviceChanged(bool)));
m_d->ui->intEdgeDetectionSize->setRange(0, 100);
m_d->ui->intEdgeDetectionSize->setExponentRatio(2.0);
......@@ -226,7 +227,8 @@ void KisToolLazyBrushOptionsWidget::slotUpdateNodeProperties()
KisSignalsBlocker b2(m_d->ui->chkUseEdgeDetection,
m_d->ui->intEdgeDetectionSize,
m_d->ui->intRadius,
m_d->ui->intCleanUp);
m_d->ui->intCleanUp,
m_d->ui->chkLimitToDevice);
// not implemented yet!
//m_d->ui->chkAutoUpdates->setEnabled(m_d->activeMask);
......@@ -254,6 +256,9 @@ void KisToolLazyBrushOptionsWidget::slotUpdateNodeProperties()
m_d->ui->intRadius->setValue(2 * (m_d->activeMask ? m_d->activeMask->fuzzyRadius() : 15));
m_d->ui->intCleanUp->setEnabled(m_d->activeMask);
m_d->ui->intCleanUp->setValue(100 * (m_d->activeMask ? m_d->activeMask->cleanUpAmount() : 0.7));
m_d->ui->chkLimitToDevice->setEnabled(m_d->activeMask);
m_d->ui->chkLimitToDevice->setChecked(m_d->activeMask && m_d->activeMask->limitToDeviceBounds());
}
void KisToolLazyBrushOptionsWidget::slotCurrentNodeChanged(KisNodeSP node)
......@@ -362,3 +367,9 @@ void KisToolLazyBrushOptionsWidget::slotCleanUpChanged(int value)
m_d->activeMask->setCleanUpAmount(qreal(value) / 100.0);
}
void KisToolLazyBrushOptionsWidget::slotLimitToDeviceChanged(bool value)
{
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask);
m_d->activeMask->setLimitToDeviceBounds(value);
}
......@@ -54,6 +54,7 @@ private Q_SLOTS:
void slotEdgeDetectionSizeChanged(int value);
void slotRadiusChanged(int value);
void slotCleanUpChanged(int value);
void slotLimitToDeviceChanged(bool value);
void slotUpdateNodeProperties();
......
......@@ -43,6 +43,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkLimitToDevice">
<property name="text">
<string>Limit to layer bounds</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
......
Markdown is supported
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