Krita

ColorizeMask.cpp
1 /*
2  * SPDX-FileCopyrightText: 2017 Wolthera van Hövell tot Westerflier <[email protected]>
3  *
4  * SPDX-License-Identifier: LGPL-2.0-or-later
5  */
6 #include "ColorizeMask.h"
7 #include <lazybrush/kis_colorize_mask.h>
8 #include <lazybrush/kis_lazy_fill_tools.h>
9 #include <kis_image.h>
10 #include "Selection.h"
11 #include <kis_selection.h>
12 #include <KoColor.h>
13 #include "kis_layer_properties_icons.h"
14 #include <kis_transaction.h>
15 #include <kis_update_scheduler.h>
16 #include <kis_undo_stores.h>
17 #include <kis_default_bounds.h>
18 
19 
20 
21 ColorizeMask::ColorizeMask(KisImageSP image, QString name, QObject *parent) :
22  Node(image, new KisColorizeMask(image,name), parent)
23 {
24 
25 }
26 
27 ColorizeMask::ColorizeMask(KisImageSP image, KisColorizeMaskSP mask, QObject *parent):
28  Node(image, mask, parent)
29 {
30 }
31 
32 ColorizeMask::~ColorizeMask()
33 {
34 
35 }
36 
37 
39 {
40  QList<ManagedColor*> colorList;
41  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
42  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, colorList);
43 
44  for (KoColor color : mask->keyStrokesColors().colors) {
45  colorList.append(new ManagedColor(color));
46  }
47 
48  return colorList;
49 }
50 
52 {
53  KisColorizeMaskSP mask = qobject_cast<KisColorizeMask*>(this->node().data());
54  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
55 
56  /**
57  * This method is supposed to to initial initialization only!
58  *
59  * It is necessary because the function also changes the color
60  * space and blending mode of the mask
61  *
62  * TODO: implement a proper API that modifies key strokes
63  * of a colorize mask without breaking undo history
64  */
65  KIS_SAFE_ASSERT_RECOVER_RETURN(mask->keyStrokesColors().colors.size() == 0);
66 
67  mask->initializeCompositeOp();
68  delete mask->setColorSpace(mask->parent()->colorSpace());
69 
71 
72  for (int i = 0; i < colors.size(); i++) {
73  KisLazyFillTools::KeyStroke keyStroke;
74  keyStroke.color = colors[i]->color();
75  keyStroke.dev = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8());
76  keyStroke.dev->setDefaultBounds(new KisDefaultBounds(this->node()->image()));
77  keyStroke.isTransparent = transparentIndex == i;
78  // NOTE: the parent node link is initialized in
79  // setKeyStrokesDirect
80 
81  keyStrokes.append(keyStroke);
82  }
83 
84  mask->setKeyStrokesDirect(keyStrokes);
85 }
86 
87 
89 {
90  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
91  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, -1);
92 
93  return mask->keyStrokesColors().transparentIndex;
94 }
95 
97 {
98  const KoColor kc = color->color();
99  KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
100  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
101 
102  mask->removeKeyStroke(kc);
103 }
104 
105 QByteArray ColorizeMask::keyStrokePixelData(ManagedColor* color, int x, int y, int w, int h) const
106 {
107  QByteArray ba;
108 
109  if (!this->node()) return ba;
110 
111  const KoColor kc = color->color();
112  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
113  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, QByteArray());
114 
115  for (KisLazyFillTools::KeyStroke keystroke : mask->fetchKeyStrokesDirect()) {
116  if (kc == keystroke.color) {
117  KisPaintDeviceSP dev = keystroke.dev;
118 
119  if (!dev) return ba;
120 
121  ba.resize(w * h * dev->pixelSize());
122  dev->readBytes(reinterpret_cast<quint8*>(ba.data()), x, y, w, h);
123  return ba;
124  }
125  }
126 
127  return ba;
128 }
129 
130 bool ColorizeMask::setKeyStrokePixelData(QByteArray value, ManagedColor* color, int x, int y, int w, int h)
131 {
132  if (!this->node()) return false;
133 
134  const KoColor kc = color->color();
135  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
136  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
137 
138  for (KisLazyFillTools::KeyStroke keystroke : mask->fetchKeyStrokesDirect()) {
139  if (kc == keystroke.color) {
140  KisPaintDeviceSP dev = keystroke.dev;
141 
142  if (!dev) return false;
143  if (value.length() < w * h * (int)dev->colorSpace()->pixelSize()) {
144  qWarning() << "ColorizeMask::setKeyStrokePixelData: not enough data to write to the paint device";
145  return false;
146  }
147  dev->writeBytes((const quint8*)value.constData(), x, y, w, h);
148  return true;
149  }
150  }
151 
152  return false;
153 }
154 
156 {
157  KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
158  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
159 
160  mask->setUseEdgeDetection(value);
161 }
162 
164 {
165  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
166  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
167 
168  return mask->useEdgeDetection();
169 }
170 
172 {
173  KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
174  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
175 
176  mask->setEdgeDetectionSize(value);
177 }
178 
180 {
181  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
182  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, -1);
183 
184  return mask->edgeDetectionSize();
185 }
186 
188 {
189  KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
190  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
191 
192  mask->setCleanUpAmount(value);
193 }
194 
196 {
197  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
198  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, -1);
199 
200  return mask->cleanUpAmount();
201 }
202 
204 {
205  KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
206  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
207 
208  mask->setLimitToDeviceBounds(value);
209 }
210 
212 {
213  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
214  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
215 
216  return mask->limitToDeviceBounds();
217 }
218 
219 void ColorizeMask::updateMask(bool force)
220 {
221  KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
222  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
223 
224  if (force) {
225  mask->forceRegenerateMask();
226  } else {
227  KisLayerPropertiesIcons::setNodePropertyAutoUndo(mask, KisLayerPropertiesIcons::colorizeNeedsUpdate, false, this->node()->image());
228  }
229 }
230 
231 void ColorizeMask::resetCache()
232 {
233  KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
234  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
235 
236  mask->resetCache();
237 }
238 
239 void ColorizeMask::setShowOutput(bool enabled)
240 {
241  KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
242  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
243 
244  KisLayerPropertiesIcons::setNodePropertyAutoUndo(mask, KisLayerPropertiesIcons::colorizeShowColoring, enabled, this->node()->image());
245 }
246 
248 {
249  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
250  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
251 
252  const KisBaseNode::PropertyList props = mask->sectionModelProperties();
253 
254  for (const KisBaseNode::Property &prop : props) {
255  if (prop.id == KisLayerPropertiesIcons::colorizeShowColoring.id()) {
256  return prop.state.toBool();
257  }
258  }
259 
260  return false;
261 }
262 
264 {
265  KisColorizeMask *mask = qobject_cast<KisColorizeMask*>(this->node().data());
266  KIS_SAFE_ASSERT_RECOVER_RETURN(mask);
267 
268  KisLayerPropertiesIcons::setNodePropertyAutoUndo(mask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, enabled, this->node()->image());
269 }
270 
272 {
273  const KisColorizeMask *mask = qobject_cast<const KisColorizeMask*>(this->node());
274  KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mask, false);
275 
276  const KisBaseNode::PropertyList props = mask->sectionModelProperties();
277 
278  for (const KisBaseNode::Property &prop : props) {
279  if (prop.id == KisLayerPropertiesIcons::colorizeEditKeyStrokes.id()) {
280  return prop.state.toBool();
281  }
282  }
283 
284  return false;
285 }
286 
288 {
289  return "colorizemask";
290 }
void append(const T &value)
void removeKeyStroke(ManagedColor *color)
removeKeyStroke Remove a color from the Colorize Mask's keystrokes.
void setLimitToDeviceBounds(bool value)
setLimitToDeviceBounds Limit the colorize mask to the combined layer bounds of the strokes and the li...
qreal cleanUpAmount() const
cleanUpAmount
bool useEdgeDetection() const
useEdgeDetection
QByteArray keyStrokePixelData(ManagedColor *color, int x, int y, int w, int h) const
keyStrokePixelData reads the given rectangle from the keystroke image data and returns it as a byte a...
int size() const const
bool limitToDeviceBounds() const
limitToDeviceBounds
qreal edgeDetectionSize() const
edgeDetectionSize
int transparencyIndex() const
transparencyIndex Index of the transparent color.
The ManagedColor class is a class to handle colors that are color managed.
Definition: ManagedColor.h:45
void setCleanUpAmount(qreal value)
setCleanUpAmount This will attempt to handle messy strokes that overlap the line art where they shoul...
void initializeKeyStrokeColors(QList< ManagedColor * > colors, int transparentIndex=-1)
initializeKeyStrokeColors Set the colors to use for the Colorize Mask's keystrokes.
Node represents a layer or mask in a Krita image's Node hierarchy.
Definition: Node.h:21
void resize(int size)
bool editKeyStrokes() const
editKeyStrokes Edit keystrokes mode allows the user to modify keystrokes on the active Colorize Mask.
const char * constData() const const
bool showOutput() const
showOutput Show output mode allows the user to see the result of the Colorize Mask's algorithm.
const char * name(StandardAction id)
void updateMask(bool force=false)
updateMask Process the Colorize Mask's keystrokes and generate a projection of the computed colors.
QList< ManagedColor * > keyStrokesColors() const
keyStrokesColors Colors used in the Colorize Mask's keystrokes.
void setEditKeyStrokes(bool enabled)
setEditKeyStrokes Toggle Colorize Mask's edit keystrokes mode.
void setShowOutput(bool enabled)
setShowOutput Toggle Colorize Mask's show output mode.
bool setKeyStrokePixelData(QByteArray value, ManagedColor *color, int x, int y, int w, int h)
setKeyStrokePixelData writes the given bytes, of which there must be enough, into the keystroke,...
void setEdgeDetectionSize(qreal value)
setEdgeDetectionSize Set the value to the thinnest line on the image.
void setUseEdgeDetection(bool value)
setUseEdgeDetection Activate this for line art with large solid areas, for example shadows on an obje...
int length() const const
virtual QString type() const override
type Krita has several types of nodes, split in layers and masks.
char * data()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Oct 1 2023 03:58:42 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.