Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_kra_savexml_visitor.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
3 * SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
9#include "kis_kra_tags.h"
10#include "kis_kra_utils.h"
12
13#include <QDir>
14
15#include <KoProperties.h>
16#include <KoColorSpace.h>
17#include <KoCompositeOp.h>
18#include <KoColorProfile.h>
19
20#include <kis_debug.h>
24#include <kis_clone_layer.h>
25#include <kis_filter_mask.h>
26#include <kis_transform_mask.h>
27#include <kis_group_layer.h>
28#include <kis_image.h>
29#include <kis_layer.h>
30#include <kis_paint_device.h>
31#include <kis_paint_layer.h>
32#include <kis_selection_mask.h>
33#include <kis_shape_layer.h>
36#include <kis_file_layer.h>
37#include <kis_psd_layer_style.h>
38#include <KisReferenceImage.h>
41#include "kis_dom_utils.h"
42
43using namespace KRA;
44
45KisSaveXmlVisitor::KisSaveXmlVisitor(QDomDocument doc, const QDomElement & element, quint32 &count, const QString &url, bool root)
47 , m_doc(doc)
48 , m_count(count)
49 , m_url(url)
50 , m_root(root)
51{
52 Q_ASSERT(!element.isNull());
53 m_elem = element;
54}
55
57{
58 m_selectedNodes = selectedNodes;
59}
60
65
67{
68 if (layer->inherits("KisReferenceImagesLayer")) {
69 return saveReferenceImagesLayer(layer);
70 } else if (layer->inherits("KisShapeLayer")) {
71 QDomElement layerElement = m_doc.createElement(LAYER);
72 saveLayer(layerElement, SHAPE_LAYER, layer);
73 m_elem.appendChild(layerElement);
74 m_count++;
75 return saveMasks(layer, layerElement);
76 }
77 else if (layer->inherits("KisFileLayer")) {
78 QDomElement layerElement = m_doc.createElement(LAYER);
79 saveLayer(layerElement, FILE_LAYER, layer);
80
81 KisFileLayer *fileLayer = dynamic_cast<KisFileLayer*>(layer);
82 KIS_ASSERT(fileLayer);
83
84 QString path = fileLayer->path();
85
86 QDir d(QFileInfo(m_url).absolutePath());
87
88#ifndef Q_OS_ANDROID
89 layerElement.setAttribute("source", d.relativeFilePath(path));
90#else
91 layerElement.setAttribute("source", path);
92#endif
93
94 if (fileLayer->scalingMethod() == KisFileLayer::ToImagePPI) {
95 layerElement.setAttribute("scale", "true");
96 }
97 else {
98 layerElement.setAttribute("scale", "false");
99 }
100 layerElement.setAttribute("scalingmethod", (int)fileLayer->scalingMethod());
101 layerElement.setAttribute(COLORSPACE_NAME, layer->original()->colorSpace()->id());
102 layerElement.setAttribute("scalingfilter", fileLayer->scalingFilter());
103
104 m_elem.appendChild(layerElement);
105 m_count++;
106 return saveMasks(layer, layerElement);
107 }
108 return false;
109}
110
111QDomElement KisSaveXmlVisitor::savePaintLayerAttributes(KisPaintLayer *layer, QDomDocument &doc, bool saveLayerOffset)
112{
113 QDomElement element = doc.createElement(LAYER);
114 saveLayer(element, PAINT_LAYER, layer);
115 element.setAttribute(CHANNEL_LOCK_FLAGS, flagsToString(layer->channelLockFlags()));
116 element.setAttribute(COLORSPACE_NAME, layer->paintDevice()->colorSpace()->id());
117
118 element.setAttribute(ONION_SKIN_ENABLED, layer->onionSkinEnabled());
119 element.setAttribute(VISIBLE_IN_TIMELINE, layer->isPinnedToTimeline());
120
121 if (!saveLayerOffset) {
122 element.removeAttribute(X);
123 element.removeAttribute(Y);
124 }
125
126 return element;
127}
128
129void KisSaveXmlVisitor::loadPaintLayerAttributes(const QDomElement &el, KisPaintLayer *layer, bool loadLayerOffset)
130{
131 QDomElement copy = el;
132
133 if (!loadLayerOffset) {
134 copy.removeAttribute(X);
135 copy.removeAttribute(Y);
136 }
137
138 loadLayerAttributes(copy, layer);
139
140 if (copy.hasAttribute(CHANNEL_LOCK_FLAGS)) {
142 }
143}
144
146{
147 QDomElement layerElement = savePaintLayerAttributes(layer, m_doc, true);
148 m_elem.appendChild(layerElement);
149 m_count++;
150 return saveMasks(layer, layerElement);
151}
152
154{
155 QDomElement layerElement;
156
157 if (m_root) // if this is the root we fake so not to save it
158 layerElement = m_elem;
159 else {
160 layerElement = m_doc.createElement(LAYER);
161 saveLayer(layerElement, GROUP_LAYER, layer);
162 layerElement.setAttribute(PASS_THROUGH_MODE, layer->passThroughMode());
163 layerElement.setAttribute(COLORSPACE_NAME, layer->colorSpace()->id());
164 layerElement.setAttribute(PROFILE, layer->colorSpace()->profile()->name());
165 m_elem.appendChild(layerElement);
166 }
167 QDomElement elem = m_doc.createElement(LAYERS);
168 Q_ASSERT(!layerElement.isNull());
169 layerElement.appendChild(elem);
170 KisSaveXmlVisitor visitor(m_doc, elem, m_count, m_url, false);
172 m_count++;
173 bool success = visitor.visitAllInverse(layer);
174
175 m_errorMessages.append(visitor.errorMessages());
176 if (!m_errorMessages.isEmpty()) {
177 return false;
178 }
179
180 QMapIterator<const KisNode*, QString> i(visitor.nodeFileNames());
181 while (i.hasNext()) {
182 i.next();
183 m_nodeFileNames[i.key()] = i.value();
184 }
185
186 i = QMapIterator<const KisNode*, QString>(visitor.keyframeFileNames());
187 while (i.hasNext()) {
188 i.next();
189 m_keyframeFileNames[i.key()] = i.value();
190 }
191
192 return success;
193}
194
196{
197 if (!layer->filter()) {
198 return false;
199 }
200 QDomElement layerElement = m_doc.createElement(LAYER);
201 saveLayer(layerElement, ADJUSTMENT_LAYER, layer);
202 layerElement.setAttribute(FILTER_NAME, layer->filter()->name());
203 layerElement.setAttribute(FILTER_VERSION, layer->filter()->version());
204 m_elem.appendChild(layerElement);
205
206 m_count++;
207 return saveMasks(layer, layerElement);
208}
209
211{
212 QDomElement layerElement = m_doc.createElement(LAYER);
213 saveLayer(layerElement, GENERATOR_LAYER, layer);
214 layerElement.setAttribute(GENERATOR_NAME, layer->filter()->name());
215 layerElement.setAttribute(GENERATOR_VERSION, layer->filter()->version());
216 m_elem.appendChild(layerElement);
217
218 m_count++;
219 return saveMasks(layer, layerElement);
220}
221
223{
224 QDomElement layerElement = m_doc.createElement(LAYER);
225 saveLayer(layerElement, CLONE_LAYER, layer);
226 layerElement.setAttribute(CLONE_FROM, layer->copyFromInfo().name());
227 layerElement.setAttribute(CLONE_FROM_UUID, layer->copyFromInfo().uuid().toString());
228 layerElement.setAttribute(CLONE_TYPE, layer->copyType());
229 m_elem.appendChild(layerElement);
230
231 m_count++;
232 return saveMasks(layer, layerElement);
233}
234
236{
237 Q_ASSERT(mask);
238 if (!mask->filter()) {
239 return false;
240 }
241 QDomElement el = m_doc.createElement(MASK);
242 saveMask(el, FILTER_MASK, mask);
243 el.setAttribute(FILTER_NAME, mask->filter()->name());
244 el.setAttribute(FILTER_VERSION, mask->filter()->version());
245
246 m_elem.appendChild(el);
247
248 m_count++;
249 return true;
250}
251
253{
254 Q_ASSERT(mask);
255
256 QDomElement el = m_doc.createElement(MASK);
257 saveMask(el, TRANSFORM_MASK, mask);
258
259 m_elem.appendChild(el);
260
261 m_count++;
262 return true;
263}
264
266{
267 Q_ASSERT(mask);
268 QDomElement el = m_doc.createElement(MASK);
269 saveMask(el, TRANSPARENCY_MASK, mask);
270 m_elem.appendChild(el);
271 m_count++;
272 return true;
273}
274
276{
277 Q_ASSERT(mask);
278 QDomElement el = m_doc.createElement(MASK);
279 saveMask(el, COLORIZE_MASK, mask);
280 m_elem.appendChild(el);
281 m_count++;
282 return true;
283}
284
286{
287 Q_ASSERT(mask);
288
289 QDomElement el = m_doc.createElement(MASK);
290 saveMask(el, SELECTION_MASK, mask);
291 m_elem.appendChild(el);
292 m_count++;
293 return true;
294}
295
296
297void KisSaveXmlVisitor::loadLayerAttributes(const QDomElement &el, KisLayer *layer)
298{
299 if (el.hasAttribute(NAME)) {
300 QString layerName = el.attribute(NAME);
301 if (layerName != layer->name()) {
302 // Make the EXR layername leading in case of conflicts
303 layer->setName(layerName);
304 }
305 }
306
307 if (el.hasAttribute(CHANNEL_FLAGS)) {
308 layer->setChannelFlags(stringToFlags(el.attribute(CHANNEL_FLAGS)));
309 }
310
311 if (el.hasAttribute(OPACITY)) {
312 layer->setOpacity(el.attribute(OPACITY).toInt());
313 }
314
315 if (el.hasAttribute(COMPOSITE_OP)) {
316 layer->setCompositeOpId(el.attribute(COMPOSITE_OP));
317 }
318
319 if (el.hasAttribute(VISIBLE)) {
320 layer->setVisible(el.attribute(VISIBLE).toInt());
321 }
322
323 if (el.hasAttribute(LOCKED)) {
324 layer->setUserLocked(el.attribute(LOCKED).toInt());
325 }
326
327 if (el.hasAttribute(X)) {
328 layer->setX(el.attribute(X).toInt());
329 }
330
331 if (el.hasAttribute(Y)) {
332 layer->setY(el.attribute(Y).toInt());
333 }
334
335 if (el.hasAttribute(UUID)) {
336 layer->setUuid(QUuid::fromString(el.attribute(UUID)));
337 }
338
339 if (el.hasAttribute(COLLAPSED)) {
340 layer->setCollapsed(el.attribute(COLLAPSED).toInt());
341 }
342
343 if (el.hasAttribute(COLOR_LABEL)) {
344 layer->setColorLabelIndex(el.attribute(COLOR_LABEL).toInt());
345 }
346
347 if (el.hasAttribute(VISIBLE_IN_TIMELINE)) {
348 layer->setPinnedToTimeline(el.attribute(VISIBLE_IN_TIMELINE).toInt());
349 }
350
351 if (el.hasAttribute(LAYER_STYLE_UUID)) {
352 QString uuidString = el.attribute(LAYER_STYLE_UUID);
353 QUuid uuid(uuidString);
354 if (!uuid.isNull()) {
355 KisPSDLayerStyleSP dumbLayerStyle(new KisPSDLayerStyle());
356 dumbLayerStyle->setUuid(uuid);
357 layer->setLayerStyle(dumbLayerStyle);
358 } else {
359 warnKrita << "WARNING: Layer style for layer" << layer->name() << "contains invalid UUID" << uuidString;
360 }
361 }
362
363 if (layer->inherits("KisShapeLayer") && el.hasAttribute(ANTIALIASED)) {
364 KisShapeLayer *shapeLayer = static_cast<KisShapeLayer*>(layer);
365 shapeLayer->setAntialiased(el.attribute(ANTIALIASED).toInt());
366 }
367}
368
369void KisSaveXmlVisitor::saveNodeKeyframes(const KisNode* node, QString nodeFilename, QDomElement& nodeElement)
370{
371 if (node->isAnimated()) {
372 QString keyframeFile = nodeFilename + ".keyframes.xml";
373 m_keyframeFileNames[node] = keyframeFile;
374 nodeElement.setAttribute(KEYFRAME_FILE, keyframeFile);
375 }
376}
377
378void KisSaveXmlVisitor::saveLayer(QDomElement & el, const QString & layerType, const KisLayer * layer)
379{
380 QString filename = LAYER + QString::number(m_count);
381
382 el.setAttribute(CHANNEL_FLAGS, flagsToString(layer->channelFlags()));
383 el.setAttribute(NAME, layer->name());
384 el.setAttribute(OPACITY, layer->opacity());
385 el.setAttribute(COMPOSITE_OP, layer->compositeOp()->id());
386 el.setAttribute(VISIBLE, layer->visible());
387 el.setAttribute(LOCKED, layer->userLocked());
388 el.setAttribute(NODE_TYPE, layerType);
389 el.setAttribute(FILE_NAME, filename);
390 el.setAttribute(X, layer->x());
391 el.setAttribute(Y, layer->y());
392 el.setAttribute(UUID, layer->uuid().toString());
393 el.setAttribute(COLLAPSED, layer->collapsed());
394 el.setAttribute(COLOR_LABEL, layer->colorLabelIndex());
395 el.setAttribute(VISIBLE_IN_TIMELINE, layer->isPinnedToTimeline());
396
397 if(layerType == SHAPE_LAYER) {
398 const KisShapeLayer *shapeLayer = static_cast<const KisShapeLayer*>(layer);
399 el.setAttribute(ANTIALIASED, shapeLayer->antialiased());
400 }
401
402 if (layer->layerStyle()) {
403 el.setAttribute(LAYER_STYLE_UUID, layer->layerStyle()->uuid().toString());
404 }
405
406 Q_FOREACH (KisNodeSP node, m_selectedNodes) {
407 if (node.data() == layer) {
408 el.setAttribute("selected", "true");
409 break;
410 }
411 }
412
413 saveNodeKeyframes(layer, filename, el);
414
415 m_nodeFileNames[layer] = filename;
416
417 dbgFile << "Saved layer "
418 << layer->name()
419 << " of type " << layerType
420 << " with filename " << LAYER + QString::number(m_count);
421}
422
423void KisSaveXmlVisitor::saveMask(QDomElement & el, const QString & maskType, const KisMaskSP mask)
424{
425 QString filename = MASK + QString::number(m_count);
426
427 el.setAttribute(NAME, mask->name());
428 el.setAttribute(VISIBLE, mask->visible());
429 el.setAttribute(LOCKED, mask->userLocked());
430 el.setAttribute(NODE_TYPE, maskType);
431 el.setAttribute(FILE_NAME, filename);
432 el.setAttribute(X, mask->x());
433 el.setAttribute(Y, mask->y());
434 el.setAttribute(UUID, mask->uuid().toString());
435 el.setAttribute(COLOR_LABEL, mask->colorLabelIndex());
436 el.setAttribute(VISIBLE_IN_TIMELINE, mask->isPinnedToTimeline());
437
438 if (maskType == SELECTION_MASK) {
439 el.setAttribute(ACTIVE, mask->nodeProperties().boolProperty("active"));
440 } else if (maskType == COLORIZE_MASK) {
441 el.setAttribute(COLORSPACE_NAME, mask->colorSpace()->id());
442 el.setAttribute(COMPOSITE_OP, mask->compositeOpId());
445
446 const KisColorizeMask *colorizeMask = dynamic_cast<const KisColorizeMask*>(mask.data());
447 KIS_SAFE_ASSERT_RECOVER_NOOP(colorizeMask);
448
449 if (colorizeMask) {
450 el.setAttribute(COLORIZE_USE_EDGE_DETECTION, colorizeMask->useEdgeDetection());
452 el.setAttribute(COLORIZE_FUZZY_RADIUS, KisDomUtils::toString(colorizeMask->fuzzyRadius()));
453 el.setAttribute(COLORIZE_CLEANUP, int(100 * colorizeMask->cleanUpAmount()));
454 el.setAttribute(COLORIZE_LIMIT_TO_DEVICE, colorizeMask->limitToDeviceBounds());
455 }
456 }
457
458 saveNodeKeyframes(mask, filename, el);
459
460 m_nodeFileNames[mask] = filename;
461
462 dbgFile << "Saved mask "
463 << mask->name()
464 << " of type " << maskType
465 << " with filename " << filename;
466}
467
468bool KisSaveXmlVisitor::saveMasks(KisNode * node, QDomElement & layerElement)
469{
470 if (node->childCount() > 0) {
471 QDomElement elem = m_doc.createElement(MASKS);
472 Q_ASSERT(!layerElement.isNull());
473 layerElement.appendChild(elem);
474 KisSaveXmlVisitor visitor(m_doc, elem, m_count, m_url, false);
476 bool success = visitor.visitAllInverse(node);
477 m_errorMessages.append(visitor.errorMessages());
478 if (!m_errorMessages.isEmpty()) {
479 return false;
480 }
481
482 QMapIterator<const KisNode*, QString> i(visitor.nodeFileNames());
483 while (i.hasNext()) {
484 i.next();
485 m_nodeFileNames[i.key()] = i.value();
486 }
487
488 i = QMapIterator<const KisNode*, QString>(visitor.keyframeFileNames());
489 while (i.hasNext()) {
490 i.next();
491 m_keyframeFileNames[i.key()] = i.value();
492 }
493
494 return success;
495 }
496 return true;
497}
498
500{
501 auto *referencesLayer = dynamic_cast<KisReferenceImagesLayer*>(layer);
502 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(referencesLayer, false);
503
504 QDomElement layerElement = m_doc.createElement(LAYER);
505 layerElement.setAttribute(NODE_TYPE, REFERENCE_IMAGES_LAYER);
506
507 int nextId = 0;
508 Q_FOREACH(KoShape *shape, referencesLayer->shapes()) {
509 auto *reference = dynamic_cast<KisReferenceImage*>(shape);
510 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(reference, false);
511 reference->saveXml(m_doc, layerElement, nextId);
512 nextId++;
513 }
514
515 m_elem.appendChild(layerElement);
516 m_count++;
517 return true;
518}
519
520
bool limitToDeviceBounds() const
qreal cleanUpAmount() const
qreal fuzzyRadius() const
bool useEdgeDetection() const
qreal edgeDetectionSize() const
The KisFileLayer class loads a particular file as a layer into the layer stack.
QString path() const
ScalingMethod scalingMethod() const
QString scalingFilter() const
static QVariant nodeProperty(KisNodeSP node, const KoID &id, const QVariant &defaultValue)
virtual KisFilterConfigurationSP filter() const
bool visitAllInverse(KisNode *node, bool breakOnFail=false)
const KoColorSpace * colorSpace() const
The KisReferenceImage class represents a single reference image.
KisSaveXmlVisitor(QDomDocument doc, const QDomElement &element, quint32 &count, const QString &url, bool root)
bool saveReferenceImagesLayer(KisExternalLayer *layer)
static void loadPaintLayerAttributes(const QDomElement &el, KisPaintLayer *layer, bool loadLayerOffset)
QMap< const KisNode *, QString > keyframeFileNames()
QMap< const KisNode *, QString > nodeFileNames()
bool visit(KisNode *) override
bool saveMasks(KisNode *node, QDomElement &layerElement)
QStringList errorMessages() const
void saveNodeKeyframes(const KisNode *node, QString filename, QDomElement &el)
QMap< const KisNode *, QString > m_nodeFileNames
void saveLayer(QDomElement &el, const QString &layerType, const KisLayer *layer)
void saveMask(QDomElement &el, const QString &maskType, const KisMaskSP mask)
QDomElement savePaintLayerAttributes(KisPaintLayer *layer, QDomDocument &doc, bool saveLayerOffset)
QMap< const KisNode *, QString > m_keyframeFileNames
static void loadLayerAttributes(const QDomElement &el, KisLayer *layer)
void setSelectedNodes(vKisNodeSP selectedNodes)
bool antialiased() const
void setAntialiased(const bool antialiased)
virtual const KoColorProfile * profile() const =0
bool boolProperty(const QString &name, bool defaultValue=false) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
@ MASK
Definition kis_brush.h:32
#define warnKrita
Definition kis_debug.h:87
#define dbgFile
Definition kis_debug.h:53
const QString COLORIZE_CLEANUP
const QString TRANSPARENCY_MASK
const QString COLORIZE_FUZZY_RADIUS
const QString Y
const QString GENERATOR_NAME
const QString FILTER_NAME
const QString CLONE_FROM
const QString CLONE_TYPE
const QString CLONE_FROM_UUID
const QString NAME
const QString VISIBLE
const QString COLORIZE_EDIT_KEYSTROKES
const QString FILE_LAYER
const QString COLOR_LABEL
const QString OPACITY
QString flagsToString(const QBitArray &flags, int size=-1, char trueToken='1', char falseToken='0', bool defaultTrue=true)
const QString X
const QString FILE_NAME
const QString PASS_THROUGH_MODE
const QString COLORIZE_EDGE_DETECTION_SIZE
const QString COMPOSITE_OP
const QString KEYFRAME_FILE
const QString PAINT_LAYER
const QString GROUP_LAYER
const QString VISIBLE_IN_TIMELINE
const QString LOCKED
const QString COLORIZE_MASK
QBitArray stringToFlags(const QString &string, int size=-1, char token='0', bool defaultTrue=true)
const QString NODE_TYPE
const QString CHANNEL_LOCK_FLAGS
const QString GENERATOR_VERSION
const QString COLLAPSED
const QString TRANSFORM_MASK
const QString COLORIZE_SHOW_COLORING
const QString ONION_SKIN_ENABLED
const QString LAYERS
const QString REFERENCE_IMAGES_LAYER
const QString COLORIZE_USE_EDGE_DETECTION
const QString FILTER_VERSION
const QString ANTIALIASED
const QString FILTER_MASK
const QString ACTIVE
const QString UUID
const QString LAYER
const QString CLONE_LAYER
const QString SHAPE_LAYER
const QString GENERATOR_LAYER
const QString PROFILE
const QString COLORSPACE_NAME
const QString SELECTION_MASK
const QString COLORIZE_LIMIT_TO_DEVICE
const QString LAYER_STYLE_UUID
const QString MASKS
const QString CHANNEL_FLAGS
const QString ADJUSTMENT_LAYER
QString toString(const QString &value)
void setPinnedToTimeline(bool pinned)
virtual void setUserLocked(bool l)
QUuid uuid() const
const QString & compositeOpId() const
void setOpacity(quint8 val)
virtual void setVisible(bool visible, bool loading=false)
bool isPinnedToTimeline() const
const KoProperties & nodeProperties() const
void setUuid(const QUuid &id)
void setColorLabelIndex(int index)
void setName(const QString &name)
void setCollapsed(bool collapsed)
int colorLabelIndex() const
bool userLocked() const
bool isAnimated() const
QString name() const
void setCompositeOpId(const QString &compositeOpId)
quint8 opacity() const
virtual bool visible(bool recursive=false) const
KisNodeUuidInfo copyFromInfo
CopyLayerType copyType() const
const KoColorSpace * colorSpace() const override
qint32 y() const override
Definition kis_layer.cc:978
QBitArray channelFlags
Definition kis_layer.cc:167
const KoCompositeOp * compositeOp() const override
returns the layer's composite op for the colorspace of the layer's parent.
Definition kis_layer.cc:232
qint32 x() const override
Definition kis_layer.cc:973
KisPSDLayerStyleSP layerStyle
Definition kis_layer.cc:171
void setX(qint32 x) override
Definition kis_layer.cc:983
virtual void setChannelFlags(const QBitArray &channelFlags)
Definition kis_layer.cc:342
KisPaintDeviceSP original() const override=0
void setLayerStyle(KisPSDLayerStyleSP layerStyle)
Definition kis_layer.cc:254
void setY(qint32 y) override
Definition kis_layer.cc:989
qint32 x() const override
Definition kis_mask.cc:431
qint32 y() const override
Definition kis_mask.cc:438
const KoColorSpace * colorSpace() const override
Definition kis_mask.cc:135
quint32 childCount() const
Definition kis_node.cpp:414
The KisPSDLayerStyle class implements loading, saving and applying the PSD layer effects.
const QBitArray & channelLockFlags() const
void setChannelLockFlags(const QBitArray &channelFlags)
KisPaintDeviceSP paintDevice
bool onionSkinEnabled() const