Krita Source Code Documentation
Loading...
Searching...
No Matches
layersplit.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2014 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "layersplit.h"
8
9#include <QMap>
10#include <QPointer>
11
12#include <klocalizedstring.h>
13#include <kpluginfactory.h>
14
15#include <KoColorSpace.h>
16#include <KoChannelInfo.h>
17#include <KoColor.h>
18
19#include <kis_debug.h>
20#include <kis_types.h>
21#include <KisViewManager.h>
22#include <kis_image.h>
23#include <kis_action.h>
24#include <KisDocument.h>
25#include <kis_node.h>
26#include <kis_painter.h>
27#include <kis_paint_device.h>
28#include <kis_paint_layer.h>
29#include <kis_group_layer.h>
31#include "dlg_layersplit.h"
32#include "kis_node_manager.h"
34#include "kis_undo_adapter.h"
35#include <KisImageBarrierLock.h>
36#include "kis_selection_mask.h"
37#include "kis_layer_utils.h"
38
39#include <KoUpdater.h>
40#include <KoProgressUpdater.h>
42
43K_PLUGIN_FACTORY_WITH_JSON(LayerSplitFactory, "kritalayersplit.json", registerPlugin<LayerSplit>();)
44
45LayerSplit::LayerSplit(QObject *parent, const QVariantList &)
46 : KisActionPlugin(parent)
47{
48 KisAction *action = createAction("layersplit");
49 connect(action, SIGNAL(triggered()), this, SLOT(slotLayerSplit()));
50}
51
55
56
68
70{
71 DlgLayerSplit dlg;
72
73 if (dlg.exec() == QDialog::Accepted) {
74
75 bool modeToLayer = !dlg.m_modeToMask;
76 dlg.hide();
77
78 KisImageSP image = viewManager()->image();
79 if (!image) return;
80
81 KisNodeSP node = viewManager()->activeNode();
82 if (!node) return;
83
84 // Convert to paint layer prior to splitting if current node is a colorize mask
85 if (node->inherits("KisColorizeMask")) {
86 std::future<KisNodeSP> convertedNode = KisLayerUtils::convertToPaintLayer(image, node);
87 node = convertedNode.get();
88 }
89
90 if (!node) return;
91
92 KisImageBarrierLock lock(image);
93
94 KisPaintDeviceSP projection = node->projection();
95 if (!projection) return;
96
97 QList<Layer> colorMap;
98
99 const KoColorSpace *cs = projection->colorSpace();
100 QRect rc = image->bounds();
101
102 int fuzziness = dlg.fuzziness();
103
104 KisCursorOverrideLock cursorLock(Qt::WaitCursor);
105
106 QPointer<KoUpdater> updater;
107 if( modeToLayer){
108 updater = viewManager()->createUnthreadedUpdater(i18n("Split into Layers"));
109 }
110 else {
111 updater = viewManager()->createUnthreadedUpdater(i18n("Split into Masks"));
112 }
113
114 updater->setProgress(0);
115
117
118 for (int row = rc.y(); row < rc.height(); ++row) {
119
120 for (int col = rc.x(); col < rc.width(); ++col) {
121
122 acc->moveTo(col, row);
123
124 KoColor c(cs);
125 c.setColor(acc->rawDataConst(), cs);
126
128 continue;
129 }
130
131 if (dlg.disregardOpacity()) {
133 }
134
135 bool found = false;
136 Q_FOREACH (const Layer &l, colorMap) {
137 if (fuzziness == 0) {
138
139 found = (l.color == c);
140 }
141 else {
142 quint8 match = cs->difference(l.color.data(), c.data());
143 found = (match <= fuzziness);
144 }
145 if (found) {
146 KisRandomAccessorSP dstAcc = l.accessor;
147 dstAcc->moveTo(col, row);
148 memcpy(dstAcc->rawData(), acc->rawDataConst(), cs->pixelSize());
149 const_cast<Layer*>(&l)->pixelsWritten++;
150 break;
151 }
152 }
153
154 if (!found) {
155 QString name = "";
156 if (dlg.palette()) {
157 name = dlg.palette()->getClosestSwatchInfo(c).swatch.name();
158 }
159
160 if (name.toLower() == "untitled" || name.toLower() == "none" || name.toLower() == "") {
161 name = KoColor::toQString(c);
162 }
163 Layer l;
164 l.color = c;
165 l.device = new KisPaintDevice(cs, name);
167 l.accessor->moveTo(col, row);
168 memcpy(l.accessor->rawData(), acc->rawDataConst(), cs->pixelSize());
169 l.pixelsWritten = 1;
170 colorMap << l;
171 }
172 }
173
174 if (updater->interrupted()) {
175 return;
176 }
177
178 updater->setProgress((row - rc.y()) * 100 / rc.height() - rc.y());
179 }
180
181 updater->setProgress(100);
182
183 dbgKrita << "Created" << colorMap.size() << "layers";
184// Q_FOREACH (const Layer &l, colorMap) {
185// dbgKrita << "\t" << l.device->objectName() << ":" << l.pixelsWritten;
186// }
187
188 if (dlg.sortLayers()) {
189 std::sort(colorMap.begin(), colorMap.end());
190 }
191
192 KisUndoAdapter *undo = image->undoAdapter();
193 undo->beginMacro(kundo2_i18n("Split Layer"));
195
196 if(modeToLayer){
197 KisGroupLayerSP baseGroup = dynamic_cast<KisGroupLayer*>(node->parent().data());
198 if (!baseGroup) {
199 // Masks are never nested
200 baseGroup = dynamic_cast<KisGroupLayer*>(node->parent()->parent().data());
201 }
202
203 if (dlg.hideOriginal()) {
204 node->setVisible(false);
205 }
206
207 if (dlg.createBaseGroup()) {
208 KisGroupLayerSP grp = new KisGroupLayer(image, i18n("Color"), OPACITY_OPAQUE_U8);
209 adapter.addNode(grp, baseGroup, 1);
210 baseGroup = grp;
211 }
212
213 Q_FOREACH (const Layer &l, colorMap) {
214 KisGroupLayerSP grp = baseGroup;
215 if (dlg.createSeparateGroups()) {
216 grp = new KisGroupLayer(image, l.device->objectName(), OPACITY_OPAQUE_U8);
217 adapter.addNode(grp, baseGroup, 1);
218 }
219 KisPaintLayerSP paintLayer = new KisPaintLayer(image, l.device->objectName(), OPACITY_OPAQUE_U8, l.device);
220 adapter.addNode(paintLayer, grp, 0);
221 paintLayer->setAlphaLocked(dlg.lockAlpha());
222 }
223 }
224 else{
225 KisLayerSP baseGroup = dynamic_cast<KisLayer*>(node.data());
226 Q_FOREACH (const Layer &l, colorMap) {
227 KisSelectionMaskSP mask = new KisSelectionMask(image);
228 mask->setName( l.device->objectName());
229
231 mask->initSelection(temp , baseGroup);
232 adapter.addNode(mask, baseGroup,0);
233 mask->setActive(true);
234 }
235 }
236
237 undo->endMacro();
238 }
239}
240
241#include "layersplit.moc"
const quint8 OPACITY_TRANSPARENT_U8
const quint8 OPACITY_OPAQUE_U8
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
int fuzziness() const
bool lockAlpha() const
KoColorSetSP palette() const
bool sortLayers() const
bool disregardOpacity() const
bool createSeparateGroups() const
bool hideOriginal() const
bool createBaseGroup() const
QPointer< KisViewManager > viewManager() const
virtual quint8 * rawData()=0
virtual const quint8 * rawDataConst() const =0
KisUndoAdapter * undoAdapter() const
QRect bounds() const override
void addNode(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis, KisImageLayerAddCommand::Flags flags=KisImageLayerAddCommand::DoRedoUpdates|KisImageLayerAddCommand::DoUndoUpdates)
KisRandomConstAccessorSP createRandomConstAccessorNG() const
const KoColorSpace * colorSpace() const
KisRandomAccessorSP createRandomAccessorNG()
static KisPaintDeviceSP convertToAlphaAsPureAlpha(KisPaintDeviceSP src)
virtual void moveTo(qint32 x, qint32 y)=0
virtual quint32 pixelSize() const =0
virtual quint8 difference(const quint8 *src1, const quint8 *src2) const =0
static QString toQString(const KoColor &color)
toQString create a user-visible string of the channel names and the channel values
Definition KoColor.cpp:655
void setColor(const quint8 *data, const KoColorSpace *colorSpace=0)
Definition KoColor.cpp:186
void setOpacity(quint8 alpha)
Definition KoColor.cpp:333
quint8 * data()
Definition KoColor.h:144
quint8 opacityU8() const
Definition KoColor.cpp:341
LayerSplit(QObject *parent, const QVariantList &)
void slotLayerSplit()
~LayerSplit() override
K_PLUGIN_FACTORY_WITH_JSON(KritaASCCDLFactory, "kritaasccdl.json", registerPlugin< KritaASCCDL >();) KritaASCCDL
#define dbgKrita
Definition kis_debug.h:45
KUndo2MagicString kundo2_i18n(const char *text)
std::future< KisNodeSP > convertToPaintLayer(KisImageSP image, KisNodeSP src)
virtual KisPaintDeviceSP projection() const =0
virtual void setVisible(bool visible, bool loading=false)
void setName(const QString &name)
void initSelection(KisSelectionSP copyFrom, KisLayerSP parentLayer)
initSelection initializes the selection for the mask from the given selection's projection.
Definition kis_mask.cc:157
KisNodeWSP parent
Definition kis_node.cpp:86
void setAlphaLocked(bool lock)
void setActive(bool active)
KisRandomAccessorSP accessor
KisPaintDeviceSP device
bool operator<(const Layer &other) const
KoColor color
int pixelsWritten