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 }