File indexing completed on 2024-05-19 04:26:54

0001 /*
0002  *  SPDX-FileCopyrightText: 2017 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 #include "ColorizeMask.h"
0007 #include <lazybrush/kis_colorize_mask.h>
0008 #include <lazybrush/kis_lazy_fill_tools.h>
0009 #include <kis_image.h>
0010 #include "Selection.h"
0011 #include <kis_selection.h>
0012 #include <KoColor.h>
0013 #include "kis_layer_properties_icons.h"
0014 #include <kis_transaction.h>
0015 #include <kis_update_scheduler.h>
0016 #include <kis_undo_stores.h>
0017 #include <kis_default_bounds.h>
0018 
0019 
0020 
0021 ColorizeMask::ColorizeMask(KisImageSP image, QString name, QObject *parent) :
0022     Node(image, new KisColorizeMask(image,name), parent)
0023 {
0024 
0025 }
0026 
0027 ColorizeMask::ColorizeMask(KisImageSP image, KisColorizeMaskSP mask, QObject *parent):
0028     Node(image, mask, parent)
0029 {
0030 }
0031 
0032 ColorizeMask::~ColorizeMask()
0033 {
0034 
0035 }
0036 
0037 
0038 QList<ManagedColor*> ColorizeMask::keyStrokesColors() const
0039 {
0040     QList<ManagedColor*> colorList;
0041     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0042     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, colorList);
0043 
0044     for (KoColor color : mask->keyStrokesColors().colors) {
0045         colorList.append(new ManagedColor(color));
0046     }
0047 
0048     return colorList;
0049 }
0050 
0051 void ColorizeMask::initializeKeyStrokeColors(QList<ManagedColor*> colors, int transparentIndex)
0052 {
0053     KisColorizeMaskSP mask = qobject_cast<KisColorizeMask*>(this->node().data());
0054     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0055 
0056     /**
0057      *  This method is supposed to to initial initialization only!
0058      *
0059      *  It is necessary because the function also changes the color
0060      *  space and blending mode of the mask
0061      *
0062      *  TODO: implement a proper API that modifies key strokes
0063      *  of a colorize mask without breaking undo history
0064      */
0065     KIS_SAFE_ASSERT_RECOVER_RETURN(mask->keyStrokesColors().colors.size() == 0);
0066 
0067     mask->initializeCompositeOp();
0068     delete mask->setColorSpace(mask->parent()->colorSpace());
0069 
0070     QList<KisLazyFillTools::KeyStroke> keyStrokes;
0071 
0072     for (int i = 0; i < colors.size(); i++) {
0073         KisLazyFillTools::KeyStroke keyStroke;
0074         keyStroke.color = colors[i]->color();
0075         keyStroke.dev = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8());
0076         keyStroke.dev->setDefaultBounds(new KisDefaultBounds(this->node()->image()));
0077         keyStroke.isTransparent = transparentIndex == i;
0078         // NOTE: the parent node link is initialized in
0079         //       setKeyStrokesDirect
0080 
0081         keyStrokes.append(keyStroke);
0082     }
0083 
0084     mask->setKeyStrokesDirect(keyStrokes);
0085 }
0086 
0087 
0088 int ColorizeMask::transparencyIndex() const
0089 {
0090     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0091     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, -1);
0092 
0093     return mask->keyStrokesColors().transparentIndex;
0094 }
0095 
0096 void ColorizeMask::removeKeyStroke(ManagedColor* color)
0097 {
0098     const KoColor kc = color->color();
0099     KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
0100     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0101 
0102     mask->removeKeyStroke(kc);
0103 }
0104 
0105 QByteArray ColorizeMask::keyStrokePixelData(ManagedColor* color, int x, int y, int w, int h) const
0106 {
0107     QByteArray ba;
0108 
0109     if (!this->node()) return ba;
0110 
0111     const KoColor kc = color->color();
0112     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0113     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, QByteArray());
0114 
0115     for (KisLazyFillTools::KeyStroke keystroke : mask->fetchKeyStrokesDirect()) {
0116         if (kc == keystroke.color) {
0117             KisPaintDeviceSP dev = keystroke.dev;
0118 
0119             if (!dev) return ba;
0120 
0121             ba.resize(w * h * dev->pixelSize());
0122             dev->readBytes(reinterpret_cast<quint8*>(ba.data()), x, y, w, h);
0123             return ba;
0124         }
0125     }
0126 
0127     return ba;
0128 }
0129 
0130 bool ColorizeMask::setKeyStrokePixelData(QByteArray value, ManagedColor* color, int x, int y, int w, int h)
0131 {
0132     if (!this->node()) return false;
0133 
0134     const KoColor kc = color->color();
0135     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0136     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
0137 
0138     for (KisLazyFillTools::KeyStroke keystroke : mask->fetchKeyStrokesDirect()) {
0139         if (kc == keystroke.color) {
0140             KisPaintDeviceSP dev = keystroke.dev;
0141 
0142             if (!dev) return false;
0143             if (value.length() <  w * h * (int)dev->colorSpace()->pixelSize()) {
0144                 qWarning() << "ColorizeMask::setKeyStrokePixelData: not enough data to write to the paint device";
0145                 return false;
0146             }
0147             dev->writeBytes((const quint8*)value.constData(), x, y, w, h);
0148             return true;
0149         }
0150     }
0151 
0152     return false;
0153 }
0154 
0155 void ColorizeMask::setUseEdgeDetection(bool value)
0156 {
0157     KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
0158     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0159 
0160     mask->setUseEdgeDetection(value);
0161 }
0162 
0163 bool ColorizeMask::useEdgeDetection() const
0164 {
0165     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0166     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
0167 
0168     return mask->useEdgeDetection();
0169 }
0170 
0171 void ColorizeMask::setEdgeDetectionSize(qreal value)
0172 {
0173     KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
0174     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0175 
0176     mask->setEdgeDetectionSize(value);
0177 }
0178 
0179 qreal ColorizeMask::edgeDetectionSize() const
0180 {
0181     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0182     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, -1);
0183 
0184     return mask->edgeDetectionSize();
0185 }
0186 
0187 void ColorizeMask::setCleanUpAmount(qreal value)
0188 {
0189     KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
0190     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0191 
0192     mask->setCleanUpAmount(value);
0193 }
0194 
0195 qreal ColorizeMask::cleanUpAmount() const
0196 {
0197     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0198     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, -1);
0199 
0200     return mask->cleanUpAmount();
0201 }
0202 
0203 void ColorizeMask::setLimitToDeviceBounds(bool value)
0204 {
0205     KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
0206     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0207 
0208     mask->setLimitToDeviceBounds(value);
0209 }
0210 
0211 bool ColorizeMask::limitToDeviceBounds() const
0212 {
0213     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0214     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
0215 
0216     return mask->limitToDeviceBounds();
0217 }
0218 
0219 void ColorizeMask::updateMask(bool force)
0220 {
0221     KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
0222     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0223 
0224     if (force) {
0225         mask->forceRegenerateMask();
0226     } else {
0227         KisLayerPropertiesIcons::setNodePropertyAutoUndo(mask, KisLayerPropertiesIcons::colorizeNeedsUpdate, false, this->node()->image());
0228     }
0229 }
0230 
0231 void ColorizeMask::resetCache()
0232 {
0233     KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
0234     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0235 
0236     mask->resetCache();
0237 }
0238 
0239 void ColorizeMask::setShowOutput(bool enabled)
0240 {
0241     KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
0242     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0243 
0244     KisLayerPropertiesIcons::setNodePropertyAutoUndo(mask, KisLayerPropertiesIcons::colorizeShowColoring, enabled, this->node()->image());
0245 }
0246 
0247 bool ColorizeMask::showOutput() const
0248 {
0249     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0250     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
0251 
0252     const KisBaseNode::PropertyList props = mask->sectionModelProperties();
0253 
0254     for (const KisBaseNode::Property &prop : props) {
0255         if (prop.id == KisLayerPropertiesIcons::colorizeShowColoring.id()) {
0256             return prop.state.toBool();
0257         }
0258     }
0259 
0260     return false;
0261 }
0262 
0263 void ColorizeMask::setEditKeyStrokes(bool enabled)
0264 {
0265     KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
0266     KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
0267 
0268     KisLayerPropertiesIcons::setNodePropertyAutoUndo(mask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, enabled, this->node()->image());
0269 }
0270 
0271 bool ColorizeMask::editKeyStrokes() const
0272 {
0273     const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
0274     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
0275 
0276     const KisBaseNode::PropertyList props = mask->sectionModelProperties();
0277 
0278     for (const KisBaseNode::Property &prop : props) {
0279         if (prop.id == KisLayerPropertiesIcons::colorizeEditKeyStrokes.id()) {
0280             return prop.state.toBool();
0281         }
0282     }
0283 
0284     return false;
0285 }
0286 
0287 QString ColorizeMask::type() const
0288 {
0289     return "colorizemask";
0290 }