Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_kra_loader.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "kis_kra_loader.h"
8
9#include <QApplication>
10#include <QStringList>
11
12#include <QMessageBox>
13
14#include <QUrl>
15#include <QBuffer>
16#include <QVersionNumber>
17
18#include <KoStore.h>
20#include <KoColorSpaceEngine.h>
21#include <KoColorProfile.h>
22#include <KoDocumentInfo.h>
23#include <KoFileDialog.h>
25#include <KoStoreDevice.h>
27#include <KoResourceServer.h>
28#include <KisResourceStorage.h>
30#include <KisResourceModel.h>
31
32#include <filter/kis_filter.h>
38#include <kis_annotation.h>
39#include <kis_base_node.h>
40#include <kis_clone_layer.h>
41#include <kis_debug.h>
42#include <kis_assert.h>
44#include <kis_filter_mask.h>
45#include <kis_transform_mask.h>
47#include <kis_group_layer.h>
48#include <kis_image.h>
49#include <kis_layer.h>
50#include <kis_name_server.h>
51#include <kis_paint_layer.h>
52#include <kis_selection.h>
53#include <kis_selection_mask.h>
54#include <kis_shape_layer.h>
57#include <kis_file_layer.h>
58#include <kis_psd_layer_style.h>
63#include "KisReferenceImage.h"
64#include <KoColorSet.h>
65
66#include "KisDocument.h"
67#include "kis_config.h"
68#include "kis_kra_tags.h"
69#include "kis_kra_utils.h"
71#include "kis_dom_utils.h"
73#include "kis_time_span.h"
74#include "kis_grid_config.h"
75#include "kis_guides_config.h"
76#include "kis_image_config.h"
80#include "KisMirrorAxisConfig.h"
82
83/*
84 Color model id comparison through the ages:
85
862.4 2.5 2.6 ideal
87
88ALPHA ALPHA ALPHA ALPHAU8
89
90CMYK CMYK CMYK CMYKAU8
91 CMYKAF32 CMYKAF32
92CMYKA16 CMYKAU16 CMYKAU16
93
94GRAYA GRAYA GRAYA GRAYAU8
95GrayF32 GRAYAF32 GRAYAF32
96GRAYA16 GRAYAU16 GRAYAU16
97
98LABA LABA LABA LABAU16
99 LABAF32 LABAF32
100 LABAU8 LABAU8
101
102RGBA RGBA RGBA RGBAU8
103RGBA16 RGBA16 RGBA16 RGBAU16
104RgbAF32 RGBAF32 RGBAF32
105RgbAF16 RgbAF16 RGBAF16
106
107XYZA16 XYZA16 XYZA16 XYZAU16
108 XYZA8 XYZA8 XYZAU8
109XyzAF16 XyzAF16 XYZAF16
110XyzAF32 XYZAF32 XYZAF32
111
112YCbCrA YCBCRA8 YCBCRA8 YCBCRAU8
113YCbCrAU16 YCBCRAU16 YCBCRAU16
114 YCBCRF32 YCBCRF32
115 */
116
117using namespace KRA;
118
120{
121public:
123 QString imageName; // used to be stored in the image, is now in the documentInfo block
124 QString imageComment; // used to be stored in the image, is now in the documentInfo block
125 QMap<KisNode*, QString> layerFilenames; // temp storage during loading
126 int syntaxVersion; // version of the fileformat we are loading
127 QVersionNumber kritaVersion;
128 vKisNodeSP selectedNodes; // the nodes that were active when saving the document.
129 QMap<QString, QString> assistantsFilenames;
133 QMap<KisNode*, QString> keyframeFilenames;
139};
140
141void convertColorSpaceNames(QString &colorspacename, QString &profileProductName) {
142 if (colorspacename == "Grayscale + Alpha") {
143 colorspacename = "GRAYA";
144 profileProductName.clear();
145 }
146 else if (colorspacename == "RgbAF32") {
147 colorspacename = "RGBAF32";
148 profileProductName.clear();
149 }
150 else if (colorspacename == "RgbAF16") {
151 colorspacename = "RGBAF16";
152 profileProductName.clear();
153 }
154 else if (colorspacename == "CMYKA16") {
155 colorspacename = "CMYKAU16";
156 }
157 else if (colorspacename == "GrayF32") {
158 colorspacename = "GRAYAF32";
159 profileProductName.clear();
160 }
161 else if (colorspacename == "GRAYA16") {
162 colorspacename = "GRAYAU16";
163 }
164 else if (colorspacename == "XyzAF16") {
165 colorspacename = "XYZAF16";
166 profileProductName.clear();
167 }
168 else if (colorspacename == "XyzAF32") {
169 colorspacename = "XYZAF32";
170 profileProductName.clear();
171 }
172 else if (colorspacename == "YCbCrA") {
173 colorspacename = "YCBCRA8";
174 }
175 else if (colorspacename == "YCbCrAU16") {
176 colorspacename = "YCBCRAU16";
177 }
178}
179
180KisKraLoader::KisKraLoader(KisDocument * document, int syntaxVersion, const QVersionNumber &kritaVersion)
181 : m_d(new Private())
182{
183 m_d->document = document;
184 m_d->syntaxVersion = syntaxVersion;
185 m_d->kritaVersion = kritaVersion;
186}
187
188
190{
191 delete m_d;
192}
193
194
195KisImageSP KisKraLoader::loadXML(const QDomElement& imageElement)
196{
197 QString attr;
198 KisImageSP image = 0;
199 qint32 width;
200 qint32 height;
201 QString profileProductName;
202 double xres;
203 double yres;
204 QString colorspacename;
205 const KoColorSpace * cs;
206
207 if ((attr = imageElement.attribute(MIME)) == NATIVE_MIMETYPE) {
208
209 if ((m_d->imageName = imageElement.attribute(NAME)).isNull()) {
210 m_d->errorMessages << i18n("Image does not have a name.");
211 return KisImageSP(0);
212 }
213
214 if ((attr = imageElement.attribute(WIDTH)).isNull()) {
215 m_d->errorMessages << i18n("Image does not specify a width.");
216 return KisImageSP(0);
217 }
218 width = KisDomUtils::toInt(attr);
219
220 if ((attr = imageElement.attribute(HEIGHT)).isNull()) {
221 m_d->errorMessages << i18n("Image does not specify a height.");
222 return KisImageSP(0);
223 }
224
225 height = KisDomUtils::toInt(attr);
226
227 m_d->imageComment = imageElement.attribute(DESCRIPTION);
228
229 xres = 100.0 / 72.0;
230 if (!(attr = imageElement.attribute(X_RESOLUTION)).isNull()) {
231 qreal value = KisDomUtils::toDouble(attr);
232
233 if (value > 0) {
234 xres = value / 72.0;
235 }
236 }
237
238 yres = 100.0 / 72.0;
239 if (!(attr = imageElement.attribute(Y_RESOLUTION)).isNull()) {
240 qreal value = KisDomUtils::toDouble(attr);
241 if (value > 0) {
242 yres = value / 72.0;
243 }
244 }
245
246 if ((colorspacename = imageElement.attribute(COLORSPACE_NAME)).isNull()) {
247 // An old file: take a reasonable default.
248 // Krita didn't support anything else in those
249 // days anyway.
250 colorspacename = "RGBA";
251 }
252
253 profileProductName = imageElement.attribute(PROFILE);
254 // A hack for an old colorspacename
255 convertColorSpaceNames(colorspacename, profileProductName);
256
257 QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id();
258 QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id();
259
260 if (profileProductName.isNull()) {
261 // no mention of profile so get default profile";
262 cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, "");
263 } else {
264 cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, profileProductName);
265 }
266
267 if (cs == 0) {
268 // try once more without the profile
269 cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, "");
270 if (cs == 0) {
271 m_d->errorMessages << i18n("Image specifies an unsupported color model: %1.", colorspacename);
272 return KisImageSP(0);
273 }
274 }
275 KisProofingConfigurationSP proofingConfig;
276 if (!(attr = imageElement.attribute(PROOFINGPROFILENAME)).isNull()) {
277 // initialize config only if ptofile name is present
278 proofingConfig = KisImageConfig(true).defaultProofingconfiguration();
279 proofingConfig->proofingProfile = attr;
280 }
281 if (proofingConfig && !(attr = imageElement.attribute(PROOFINGMODEL)).isNull()) {
282 proofingConfig->proofingModel = attr;
283 }
284 if (proofingConfig && !(attr = imageElement.attribute(PROOFINGDEPTH)).isNull()) {
285 proofingConfig->proofingDepth = attr;
286 }
287 if (proofingConfig && !(attr = imageElement.attribute(PROOFINGINTENT)).isNull()) {
288 proofingConfig->conversionIntent = (KoColorConversionTransformation::Intent) KisDomUtils::toInt(attr);
289 }
290 if (proofingConfig && !(attr = imageElement.attribute(PROOFINGDISPLAYINTENT)).isNull()) {
291 proofingConfig->displayIntent = (KoColorConversionTransformation::Intent) KisDomUtils::toInt(attr);
292 }
293 if (proofingConfig && !(attr = imageElement.attribute(PROOFINGDISPLAYMODE)).isNull()) {
294 if (attr == "monitor") {
295 proofingConfig->displayMode = KisProofingConfiguration::Monitor;
296 } else if (attr == "paper") {
297 proofingConfig->displayMode = KisProofingConfiguration::Paper;
298 } else {
299 proofingConfig->displayMode = KisProofingConfiguration::Custom;
300 }
301 }
302 if (proofingConfig && !(attr = imageElement.attribute(PROOFINGBLACKPOINTCOMPENSATION)).isNull()) {
303 proofingConfig->useBlackPointCompensationFirstTransform = (attr == "true");
304 }
305
306 if (proofingConfig && !(attr = imageElement.attribute(PROOFINGDISPLAYBLACKPOINTCOMPENSATION)).isNull()) {
307 proofingConfig->displayFlags.setFlag(KoColorConversionTransformation::BlackpointCompensation, attr == "true");
308 }
309
310 if (proofingConfig && !(attr = imageElement.attribute(PROOFINGADAPTATIONSTATE)).isNull()) {
311 const qreal legacyAdaptationState = KisDomUtils::toDouble(attr);
312 proofingConfig->setLegacyAdaptationState(legacyAdaptationState);
313 }
314
315 if (m_d->document) {
316 image = new KisImage(m_d->document->createUndoStore(), width, height, cs, m_d->imageName);
317 }
318 else {
319 image = new KisImage(0, width, height, cs, m_d->imageName);
320 }
321 image->setResolution(xres, yres);
322 loadNodes(imageElement, image, const_cast<KisGroupLayer*>(image->rootLayer().data()));
323
324
325 QDomNode child;
326 for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
327 QDomElement e = child.toElement();
328
329 if(e.tagName() == CANVASPROJECTIONCOLOR) {
330 if (e.hasAttribute(COLORBYTEDATA)) {
331 QByteArray colorData = QByteArray::fromBase64(e.attribute(COLORBYTEDATA).toLatin1());
332 KoColor color((const quint8*)colorData.data(), image->colorSpace());
333 image->setDefaultProjectionColor(color);
334 }
335 }
336
337 if(e.tagName() == COLORHISTORY) {
338 QList<KoColor> colors = loadKoColors(e);
339 m_d->document->setColorHistory(colors);
340 }
341
342 if(e.tagName() == GLOBALASSISTANTSCOLOR) {
343 if (e.hasAttribute(SIMPLECOLORDATA)) {
344 QString colorData = e.attribute(SIMPLECOLORDATA);
346 }
347 }
348
349 if (proofingConfig && e.tagName()== PROOFINGWARNINGCOLOR) {
350 QDomDocument dom;
351 QDomNode node = e;
352 dom.appendChild(dom.importNode(node, true));
353 QDomElement eq = dom.firstChildElement();
354 proofingConfig->warningColor = KoColor::fromXML(eq.firstChildElement(), Integer8BitsColorDepthID.id());
355 }
356
357 // COMPATIBILITY -- Load Animation Metadata from OLD KRA files.
358 if (e.tagName().toLower() == "animation") {
360 }
361 }
362
363 if (proofingConfig) {
364 image->setProofingConfiguration(proofingConfig);
365 }
366
367 for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
368 QDomElement e = child.toElement();
369 if (e.tagName() == "compositions") {
370 loadCompositions(e, image);
371 }
372 }
373 }
374
375 QDomNode child;
376 for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
377 QDomElement e = child.toElement();
378 if (e.tagName() == "grid") {
379 loadGrid(e);
380 } else if (e.tagName() == "guides") {
381 loadGuides(e);
382 } else if (e.tagName() == MIRROR_AXIS) {
384 } else if (e.tagName() == "assistants") {
386 } else if (e.tagName() == "audio") {
388 }
389 }
390
391 // reading palettes from XML
392 for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
393 QDomElement e = child.toElement();
394 if (e.tagName() == PALETTES) {
395 for (QDomElement paletteElement = e.lastChildElement(); !paletteElement.isNull();
396 paletteElement = paletteElement.previousSiblingElement()) {
397 QString paletteName = paletteElement.attribute("filename");
398 m_d->paletteFilenames.append(paletteName);
399 }
400 break;
401 }
402 }
403
404 // reading resources from XML
405 for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
406 QDomElement e = child.toElement();
407 if (e.tagName() == RESOURCES) {
408 for (QDomElement resourceElement = e.lastChildElement();
409 !resourceElement.isNull();
410 resourceElement = resourceElement.previousSiblingElement())
411 {
412 KoResourceSignature resourceItem;
413 resourceItem.filename = resourceElement.attribute("filename");
414 resourceItem.md5sum = resourceElement.attribute("md5sum");
415 resourceItem.type = resourceElement.attribute("type");
416 resourceItem.name = resourceElement.attribute("name");
417 m_d->resources.append(resourceItem);
418 }
419 break;
420 }
421 }
422
423 // reading the extra annotations from XML
424 for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
425 QDomElement e = child.toElement();
426 if (e.tagName() == ANNOTATIONS) {
427 for (QDomElement annotationElement = e.firstChildElement();
428 !annotationElement.isNull();
429 annotationElement = annotationElement.nextSiblingElement())
430 {
431 QString type = annotationElement.attribute("type");
432 QString description = annotationElement.attribute("description");
433
434 KisAnnotationSP annotation = new KisAnnotation(type, description, QByteArray());
435 m_d->annotations << annotation;
436 }
437 break;
438 }
439 }
440
441 return image;
442}
443
444void KisKraLoader::loadBinaryData(KoStore * store, KisImageSP image, const QString & uri, bool external)
445{
446 // icc profile: if present, this overrides the profile product name loaded in loadXML.
447 QString location = external ? QString() : uri;
448 location += m_d->imageName + ICC_PATH;
449 if (store->hasFile(location)) {
450 if (store->open(location)) {
451 QByteArray data; data.resize(store->size());
452 bool res = (store->read(data.data(), store->size()) > -1);
453 store->close();
454 if (res) {
455 QString colorspaceModel = image->colorSpace()->colorModelId().id();
456 QString colorspaceDepth = image->colorSpace()->colorDepthId().id();
457 const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(colorspaceModel, image->colorSpace()->colorDepthId().id(), data);
458 if (profile && profile->valid()) {
459 const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, profile);
460 image->convertImageProjectionColorSpace(colorSpace);
461 }
462 }
463 }
464 }
465 //load the embed proofing profile, it only needs to be loaded into Krita, not assigned.
466 location = external ? QString() : uri;
467 location += m_d->imageName + ICC_PROOFING_PATH;
468 if (store->hasFile(location)) {
469 if (store->open(location)) {
470 QByteArray proofingData;
471 proofingData.resize(store->size());
472 bool proofingProfileRes = (store->read(proofingData.data(), store->size())>-1);
473 store->close();
474
475 KisProofingConfigurationSP proofingConfig = image->proofingConfiguration();
476 if (!proofingConfig) {
477 proofingConfig = KisImageConfig(true).defaultProofingconfiguration();
478 }
479
480 if (proofingProfileRes) {
481 const KoColorProfile *proofingProfile = KoColorSpaceRegistry::instance()->createColorProfile(proofingConfig->proofingModel, proofingConfig->proofingDepth, proofingData);
482 if (proofingProfile->valid()){
483 KoColorSpaceRegistry::instance()->addProfile(proofingProfile);
484 }
485 }
486 }
487 }
488
489
490 // Load the layers data: if there is a profile associated with a layer it will be set now.
492
493 if (external) {
494 visitor.setExternalUri(uri);
495 }
496
497 image->rootLayer()->accept(visitor);
498 if (!visitor.errorMessages().isEmpty()) {
499 m_d->errorMessages.append(visitor.errorMessages());
500 }
501 if (!visitor.warningMessages().isEmpty()) {
502 m_d->warningMessages.append(visitor.warningMessages());
503 }
504
505 // annotations
506 // exif
507 location = external ? QString() : uri;
508 location += m_d->imageName + EXIF_PATH;
509 if (store->hasFile(location)) {
510 QByteArray data;
511 store->open(location);
512 data = store->read(store->size());
513 store->close();
514 image->addAnnotation(KisAnnotationSP(new KisAnnotation("exif", "", data)));
515 }
516
517
518 // layer styles
519 location = external ? QString() : uri;
520 location += m_d->imageName + LAYER_STYLES_PATH;
521 if (store->hasFile(location)) {
522
524 store->open(location);
525 {
526 KoStoreDevice device(store);
527 device.open(QIODevice::ReadOnly);
528
533 QByteArray buf = device.readAll();
534 QBuffer raDevice(&buf);
535 raDevice.open(QIODevice::ReadOnly);
536 serializer.readFromDevice(raDevice);
537 }
538 store->close();
539
540 if (serializer.isValid()) {
541 const QString resourceLocation = m_d->document->embeddedResourcesStorageId();
542 serializer.assignAllLayerStylesToLayers(image->root(), resourceLocation);
543
544 } else {
545 warnKrita << "WARNING: Couldn't load layer styles library from .kra!";
546 }
547 }
548
549 if (m_d->document && m_d->document->documentInfo()->aboutInfo("title").isNull())
551 if (m_d->document && m_d->document->documentInfo()->aboutInfo("comment").isNull())
553
554 loadAssistants(store, uri, external);
555
556 // Annotations
557 Q_FOREACH(KisAnnotationSP annotation, m_d->annotations) {
558 QByteArray ba;
559 location = external ? QString() : uri;
560 location += m_d->imageName + ANNOTATIONS_PATH + annotation->type();
561 if (store->hasFile(location)) {
562 store->open(location);
563 KoStoreDevice device(store);
564 device.open(QIODevice::ReadOnly);
565 ba = device.readAll();
566 device.close();
567 store->close();
568 annotation->setAnnotation(ba);
569 m_d->document->image()->addAnnotation(annotation);
570 }
571 }
572
573}
574
576{
578 Q_FOREACH (const QString &filename, m_d->paletteFilenames) {
579 KoColorSetSP newPalette(new KoColorSet(filename));
580 store->open(m_d->imageName + PALETTE_PATH + filename);
581
582 QByteArray data = store->read(store->size());
583 if (data.size() > 0) {
584 newPalette->fromByteArray(data, KisGlobalResourcesInterface::instance());
585 store->close();
586 list.append(newPalette);
587 } else {
588 m_d->warningMessages.append(i18nc("Warning message on loading a .kra file", "Embedded palette is empty and cannot be loaded. The name of the palette: %1", filename));
589 }
590 }
591 doc->setPaletteList(list);
592
593 Q_FOREACH(const KoResourceSignature &resourceItem, m_d->resources) {
594 KisResourceModel model(resourceItem.type);
595 if (model.resourcesForMD5(resourceItem.md5sum).isEmpty()) {
596 store->open(RESOURCE_PATH + '/' + resourceItem.type + '/' + resourceItem.filename);
597
598 if (!store->isOpen()) {
599 m_d->warningMessages.append(i18nc("Warning message on loading a .kra file", "Embedded resource cannot be read. The filename of the resource: %1", resourceItem.filename));
600 continue;
601 }
602
605 if (!store->device()->atEnd() && !doc->linkedResourcesStorageId().isEmpty()) {
606 bool result = bool(model.importResource(resourceItem.filename, store->device(), false, doc->linkedResourcesStorageId()));
607 if (!result) {
608 m_d->warningMessages.append(i18nc("Warning message on loading a .kra file", "Embedded resource cannot be imported. The filename of the resource: %1", resourceItem.filename));
609 }
610 }
611
612 store->close();
613 }
614 }
615}
616
618{
619 if (!store->hasFile(m_d->imageName + STORYBOARD_PATH + "index.xml")) return;
620
621 if (store->open(m_d->imageName + STORYBOARD_PATH + "index.xml")) {
622 QByteArray data = store->read(store->size());
623 QDomDocument document;
624 document.setContent(data);
625 store->close();
626
627 QDomElement root = document.documentElement();
628 QDomNode node;
629 for (node = root.lastChild(); !node.isNull(); node = node.previousSibling()) {
630 if (node.isElement()) {
631 QDomElement element = node.toElement();
632 if (element.tagName() == "StoryboardItemList") {
633 loadStoryboardItemList(element);
634 } else if (element.tagName() == "StoryboardCommentList") {
636 }
637 }
638 }
639 }
640}
641
643{
644 if (!store->hasFile(m_d->imageName + ANIMATION_METADATA_PATH + "index.xml")) return;
645
646 if (store->open(m_d->imageName + ANIMATION_METADATA_PATH + "index.xml")) {
647 QByteArray data = store->read(store->size());
648 QDomDocument document;
649 document.setContent(data);
650 store->close();
651
652 QDomElement root = document.documentElement();
653 loadAnimationMetadataFromXML(root, image);
654 }
655}
656
658{
659 if (!store->hasFile(m_d->imageName + AUDIO_PATH + "index.xml")) return;
660
661 if (store->open(m_d->imageName + AUDIO_PATH + "index.xml")) {
662 QByteArray byteData = store->read(store->size());
663 QDomDocument xmlDocument;
664 xmlDocument.setContent(byteData);
665 store->close();
666
667 QDomElement root = xmlDocument.documentElement();
668 loadAudioXML(xmlDocument, root, kisDoc);
669 }
670}
671
672void KisKraLoader::backCompat_loadAudio(const QDomElement& elem, KisImageSP image, KisDocument *document)
673{
674 QDomDocument dom;
675 dom.appendChild(dom.importNode(elem, true));
676 QDomElement qElement = dom.firstChildElement();
677
678 QString fileName;
679 if (KisDomUtils::loadValue(qElement, "masterChannelPath", &fileName)) {
680 fileName = QDir::toNativeSeparators(fileName);
681
682 QDir baseDirectory = QFileInfo(m_d->document->localFilePath()).absoluteDir();
683 fileName = QDir::cleanPath( baseDirectory.filePath(fileName) );
684
685 QFileInfo info(fileName);
686
687 if (!info.exists()) {
688 KisCursorOverrideHijacker cursorHijacker;
689
690 QString msg = i18nc(
691 "@info",
692 "Audio channel file \"%1\" doesn't exist!\n\n"
693 "Expected path:\n"
694 "%2\n\n"
695 "Do you want to locate it manually?", info.fileName(), info.absoluteFilePath());
696
697 int result = QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "File not found"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
698
699 if (result == QMessageBox::Yes) {
700 info.setFile(KisImportExportManager::askForAudioFileName(info.absolutePath(), 0));
701 }
702 }
703
704 if (info.exists()) {
705 QVector<QFileInfo> clipFiles;
706
707 clipFiles << info;
708
709 document->setAudioTracks(clipFiles);
710 }
711 }
712
713 // Note: Muting has been removed from backCompat due to it no longer being document-specific.
714
715 qreal audioVolume = 1.0;
716 if (KisDomUtils::loadValue(qElement, "audioVolume", &audioVolume)) {
717 document->setAudioVolume(audioVolume);
718 }
719}
720
725
730
735
740
745
750
752{
753 return m_d->imageName;
754}
755
756
757void KisKraLoader::loadAssistants(KoStore *store, const QString &uri, bool external)
758{
759 QString file_path;
760 QString location;
761 QMap<int ,KisPaintingAssistantHandleSP> handleMap;
762 KisPaintingAssistant* assistant = 0;
763 const QColor globalColor = m_d->document->assistantsGlobalColor();
764
765 QMap<QString,QString>::const_iterator loadedAssistant = m_d->assistantsFilenames.constBegin();
766 while (loadedAssistant != m_d->assistantsFilenames.constEnd()){
767 const KisPaintingAssistantFactory* factory = KisPaintingAssistantFactoryRegistry::instance()->get(loadedAssistant.value());
768 if (factory) {
769 assistant = factory->createPaintingAssistant();
770 location = external ? QString() : uri;
771 location += m_d->imageName + ASSISTANTS_PATH;
772 file_path = location + loadedAssistant.key();
773 assistant->loadXml(store, handleMap, file_path);
774 assistant->setAssistantGlobalColorCache(globalColor);
775
776 //If an assistant has too few handles than it should according to it's own setup, just don't load it//
777 if (assistant->handles().size()==assistant->numHandles()){
778 m_d->assistants.append(toQShared(assistant));
779 }
780 }
781 loadedAssistant++;
782 }
783}
784
785void KisKraLoader::loadAnimationMetadataFromXML(const QDomElement &element, KisImageSP image)
786{
787 QDomDocument qDom;
788 QDomNode node = element;
789 qDom.appendChild(qDom.importNode(node, true));
790 QDomElement rootElement = qDom.firstChildElement();
791
792 float framerate;
793 KisTimeSpan range;
794 int currentTime;
795 QString string;
796
798
799 if (KisDomUtils::loadValue(rootElement, "framerate", &framerate)) {
800 animation->setFramerate(framerate);
801 }
802
803 if (KisDomUtils::loadValue(rootElement, "range", &range)) {
804 animation->setDocumentRange(range);
805 }
806
807 if (KisDomUtils::loadValue(rootElement, "currentTime", &currentTime)) {
808 animation->switchCurrentTimeAsync(currentTime);
809 }
810
811 {
812 int initialFrameNumber = -1;
813 QDomElement exportElement = rootElement.firstChildElement("export-settings");
814 if (!exportElement.isNull()) {
815 if (KisDomUtils::loadValue(exportElement, "sequenceFilePath", &string)) {
816 animation->setExportSequenceFilePath(string);
817 }
818
819 if (KisDomUtils::loadValue(exportElement, "sequenceBaseName", &string)) {
820 animation->setExportSequenceBaseName(string);
821 }
822
823 if (KisDomUtils::loadValue(exportElement, "sequenceInitialFrameNumber", &initialFrameNumber)) {
824 animation->setExportInitialFrameNumber(initialFrameNumber);
825 }
826 }
827 }
828
829 animation->setExportSequenceBaseName(string);
830}
831
832KisNodeSP KisKraLoader::loadNodes(const QDomElement& element, KisImageSP image, KisNodeSP parent)
833{
834
835 QDomNode node = element.firstChild();
836 QDomNode child;
837
838 if (!node.isNull()) {
839
840 if (node.isElement()) {
841
842 // See https://bugs.kde.org/show_bug.cgi?id=408963, where there is a selection mask that is a child of the
843 // the projection. That needs to be treated as a global selection, so we keep track of those.
844 vKisNodeSP topLevelSelectionMasks;
845 if (node.nodeName().toUpper() == LAYERS.toUpper() || node.nodeName().toUpper() == MASKS.toUpper()) {
846 for (child = node.lastChild(); !child.isNull(); child = child.previousSibling()) {
847 KisNodeSP node = loadNode(child.toElement(), image);
848
849 if (node && parent.data() == image->rootLayer().data() && node->inherits("KisSelectionMask") && image->rootLayer()->childCount() > 0) {
850 topLevelSelectionMasks << node;
851 continue;
852 }
853
854 if (node ) {
855 image->addNode(node, parent);
856 if (node->inherits("KisLayer") && child.childNodes().count() > 0) {
857 loadNodes(child.toElement(), image, node);
858 }
859 }
860 }
861
862 KisSelectionMaskSP activeSelectionMask;
863 Q_FOREACH (KisNodeSP node, topLevelSelectionMasks) {
864 KisSelectionMask *mask = qobject_cast<KisSelectionMask*>(node.data());
865 if (mask->active()) {
866 if (activeSelectionMask) {
867 m_d->warningMessages << i18n("Two global selection masks in active state found. \"%1\" is kept active, \"%2\" is deactivated", activeSelectionMask->name(), mask->name());
868 mask->setActive(false);
869 KIS_ASSERT(!mask->active());
870 } else {
871 activeSelectionMask = mask;
872 }
873 }
874
875 image->addNode(mask, parent);
876 }
877 }
878 }
879 }
880
881 return parent;
882}
883
885
886KisNodeSP KisKraLoader::loadNode(const QDomElement& element, KisImageSP image)
887{
888 // Nota bene: If you add new properties to layers, you should
889 // ALWAYS define a default value in case the property is not
890 // present in the layer definition: this helps a LOT with backward
891 // compatibility.
892 QString name = element.attribute(NAME, "No Name");
893
894 QUuid id = QUuid(element.attribute(UUID, QUuid().toString()));
895
896 qint32 x = element.attribute(X, "0").toInt();
897 qint32 y = element.attribute(Y, "0").toInt();
898
899 qint32 opacity = element.attribute(OPACITY, QString::number(OPACITY_OPAQUE_U8)).toInt();
900 if (opacity < OPACITY_TRANSPARENT_U8) opacity = OPACITY_TRANSPARENT_U8;
901 if (opacity > OPACITY_OPAQUE_U8) opacity = OPACITY_OPAQUE_U8;
902
903 const KoColorSpace* colorSpace = 0;
904 if ((element.attribute(COLORSPACE_NAME)).isNull()) {
905 dbgFile << "No attribute color space for layer: " << name;
906 colorSpace = image->colorSpace();
907 } else {
908 QString colorspacename = element.attribute(COLORSPACE_NAME);
909 QString profileProductName = element.attribute(PROFILE);
910
911 convertColorSpaceNames(colorspacename, profileProductName);
912
913 QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id();
914 QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id();
915 dbgFile << "Searching color space: " << colorspacename << colorspaceModel << colorspaceDepth << " for layer: " << name;
916 // use default profile - it will be replaced later in completeLoading
917
918 if (profileProductName.isNull()) {
919 // no mention of profile so get default profile";
920 colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, "");
921 } else {
922 colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, profileProductName);
923 }
924
925 dbgFile << "found colorspace" << colorSpace;
926 if (!colorSpace) {
927 m_d->warningMessages << i18n("Layer %1 specifies an unsupported color model: %2.", name, colorspacename);
928 return 0;
929 }
930 }
931
932 const bool visible = element.attribute(VISIBLE, "1") == "0" ? false : true;
933 const bool locked = element.attribute(LOCKED, "0") == "0" ? false : true;
934 const bool collapsed = element.attribute(COLLAPSED, "0") == "0" ? false : true;
935 int colorLabelIndex = element.attribute(COLOR_LABEL, "0").toInt();
937 if (colorLabelIndex >= labels.size()) {
938 colorLabelIndex = labels.size() - 1;
939 }
940
941 // Now find out the layer type and do specific handling
942 QString nodeType;
943
944 if (m_d->syntaxVersion == 1) {
945 nodeType = element.attribute("layertype");
946 if (nodeType.isEmpty()) {
948 }
949 }
950 else {
951 nodeType = element.attribute(NODE_TYPE);
952 }
953
954 if (nodeType.isEmpty()) {
955 m_d->warningMessages << i18n("Layer %1 has an unsupported type.", name);
956 return 0;
957 }
958
959
960
961 KisNodeSP node = 0;
962
963 if (nodeType == PAINT_LAYER)
964 node = loadPaintLayer(element, image, name, colorSpace, opacity);
965 else if (nodeType == GROUP_LAYER)
966 node = loadGroupLayer(element, image, name, colorSpace, opacity);
967 else if (nodeType == ADJUSTMENT_LAYER)
968 node = loadAdjustmentLayer(element, image, name, colorSpace, opacity);
969 else if (nodeType == SHAPE_LAYER)
970 node = loadShapeLayer(element, image, name, colorSpace, opacity);
971 else if (nodeType == GENERATOR_LAYER)
972 node = loadGeneratorLayer(element, image, name, colorSpace, opacity);
973 else if (nodeType == CLONE_LAYER)
974 node = loadCloneLayer(element, image, name, colorSpace, opacity);
975 else if (nodeType == FILTER_MASK)
976 node = loadFilterMask(image, element);
977 else if (nodeType == TRANSFORM_MASK)
978 node = loadTransformMask(image, element);
979 else if (nodeType == TRANSPARENCY_MASK)
980 node = loadTransparencyMask(image, element);
981 else if (nodeType == SELECTION_MASK)
982 node = loadSelectionMask(image, element);
983 else if (nodeType == COLORIZE_MASK)
984 node = loadColorizeMask(image, element, colorSpace);
985 else if (nodeType == FILE_LAYER)
986 node = loadFileLayer(element, image, name, opacity, colorSpace);
988 node = loadReferenceImagesLayer(element, image);
989 else {
990 m_d->warningMessages << i18n("Layer %1 has an unsupported type: %2.", name, nodeType);
991 return 0;
992 }
993
994 // Loading the node went wrong. Return empty node and leave to
995 // upstream to complain to the user
996 if (!node) {
997 m_d->warningMessages << i18n("Failure loading layer %1 of type: %2.", name, nodeType);
998 return 0;
999 }
1000
1001 node->setVisible(visible, true);
1002 node->setUserLocked(locked);
1003 node->setCollapsed(collapsed);
1004 node->setColorLabelIndex(colorLabelIndex);
1005 node->setX(x);
1006 node->setY(y);
1007 node->setName(name);
1008
1009 if (! id.isNull()) // if no uuid in file, new one has been generated already
1010 node->setUuid(id);
1011
1012 if (node->inherits("KisLayer") || node->inherits("KisColorizeMask")) {
1013 QString compositeOpName = element.attribute(COMPOSITE_OP, "normal");
1014 node->setCompositeOpId(compositeOpName);
1015
1016 if (m_d->kritaVersion < QVersionNumber(5, 2) &&
1017 colorSpace->colorModelId() == CMYKAColorModelID &&
1018 subtractiveBlendingModesInCmyk().contains(compositeOpName)) {
1019
1021 i18n("Layer \"%1\" has blending mode \"%2\" that has changed its "
1022 "behavior for CMYK color in Krita 5.2. Please check the "
1023 "result and consider enabling legacy \"Additive\" algorithm in "
1024 "Settings->Configure Krita->General->Tools->CMYK blending mode",
1025 name, KoCompositeOpRegistry::instance().getKoID(compositeOpName).name());
1026 }
1027 }
1028
1029 if (node->inherits("KisLayer")) {
1030 KisLayer* layer = qobject_cast<KisLayer*>(node.data());
1031 QBitArray channelFlags = stringToFlags(element.attribute(CHANNEL_FLAGS, ""), colorSpace->channelCount());
1032 layer->setChannelFlags(channelFlags);
1033
1034 if (element.hasAttribute(LAYER_STYLE_UUID)) {
1035 QString uuidString = element.attribute(LAYER_STYLE_UUID);
1036 QUuid uuid(uuidString);
1037 if (!uuid.isNull()) {
1038 KisPSDLayerStyleSP dumbLayerStyle(new KisPSDLayerStyle());
1039 dumbLayerStyle->setUuid(uuid);
1040 layer->setLayerStyle(dumbLayerStyle->cloneWithResourcesSnapshot(KisGlobalResourcesInterface::instance(), 0));
1041 } else {
1042 warnKrita << "WARNING: Layer style for layer" << layer->name() << "contains invalid UUID" << uuidString;
1043 }
1044 }
1045 }
1046
1047 if (node->inherits("KisGroupLayer")) {
1048 if (element.hasAttribute(PASS_THROUGH_MODE)) {
1049 bool value = element.attribute(PASS_THROUGH_MODE, "0") != "0";
1050
1051 KisGroupLayer *group = qobject_cast<KisGroupLayer*>(node.data());
1052 group->setPassThroughMode(value);
1053 }
1054 }
1055
1056 if (node->inherits("KisShapeLayer")) {
1057 if (element.hasAttribute(ANTIALIASED)) {
1058 bool value = element.attribute(ANTIALIASED, "0") != "0";
1059
1060 KisShapeLayer *shapeLayer = qobject_cast<KisShapeLayer*>(node.data());
1061 shapeLayer->setAntialiased(value);
1062 }
1063 }
1064
1065
1066 const bool timelineEnabled = element.attribute(VISIBLE_IN_TIMELINE, "0") == "0" ? false : true;
1067 node->setPinnedToTimeline(timelineEnabled);
1068
1069 if (node->inherits("KisPaintLayer")) {
1070 KisPaintLayer* layer = qobject_cast<KisPaintLayer*>(node.data());
1071 QBitArray channelLockFlags = stringToFlags(element.attribute(CHANNEL_LOCK_FLAGS, ""), colorSpace->channelCount());
1072 layer->setChannelLockFlags(channelLockFlags);
1073
1074 bool onionEnabled = element.attribute(ONION_SKIN_ENABLED, "0") == "0" ? false : true;
1075 layer->setOnionSkinEnabled(onionEnabled);
1076 }
1077
1078 if (element.attribute(FILE_NAME).isNull()) {
1079 m_d->layerFilenames[node.data()] = name;
1080 }
1081 else {
1082 m_d->layerFilenames[node.data()] = element.attribute(FILE_NAME);
1083 }
1084
1085 if (element.hasAttribute("selected") && element.attribute("selected") == "true") {
1086 m_d->selectedNodes.append(node);
1087 }
1088
1089 if (element.hasAttribute(KEYFRAME_FILE)) {
1090 m_d->keyframeFilenames.insert(node.data(), element.attribute(KEYFRAME_FILE));
1091 }
1092
1093 return node;
1094}
1095
1096
1097KisNodeSP KisKraLoader::loadPaintLayer(const QDomElement& element, KisImageSP image,
1098 const QString& name, const KoColorSpace* cs, quint32 opacity)
1099{
1100 Q_UNUSED(element);
1101 KisPaintLayer* layer;
1102
1103 layer = new KisPaintLayer(image, name, opacity, cs);
1104 Q_CHECK_PTR(layer);
1105 return layer;
1106
1107}
1108
1109KisNodeSP KisKraLoader::loadFileLayer(const QDomElement& element, KisImageSP image, const QString& name, quint32 opacity, const KoColorSpace *fallbackColorSpace)
1110{
1111 QString filename = element.attribute("source", QString());
1112 if (filename.isNull()) return 0;
1113 bool scale = (element.attribute("scale", "true") == "true");
1114 int scalingMethod = element.attribute("scalingmethod", "-1").toInt();
1115 if (scalingMethod < 0) {
1116 if (scale) {
1117 scalingMethod = KisFileLayer::ToImagePPI;
1118 }
1119 else {
1120 scalingMethod = KisFileLayer::None;
1121 }
1122 }
1123 QString scalingFilter = element.attribute("scalingfilter", "Bicubic");
1124
1125 QString documentPath;
1126 if (m_d->document) {
1127 documentPath = m_d->document->path();
1128 }
1129 QFileInfo info(documentPath);
1130 QString basePath = info.absolutePath();
1131
1132#ifndef Q_OS_ANDROID
1133 QString fullPath = QDir(basePath).filePath(QDir::cleanPath(filename));
1134#else
1135 QString fullPath = filename;
1136#endif
1137 if (!QFileInfo(fullPath).exists()) {
1138 KisCursorOverrideHijacker cursorHijacker;
1139
1140 QString msg = i18nc(
1141 "@info",
1142 "The file associated to a file layer with the name \"%1\" is not found.\n\n"
1143 "Expected path:\n"
1144 "%2\n\n"
1145 "Do you want to locate it manually?", name, fullPath);
1146
1147 int result = QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "File not found"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
1148
1149 if (result == QMessageBox::Yes) {
1150
1151 KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument");
1153 dialog.setDefaultDir(basePath);
1154 QString url = dialog.filename();
1155
1156 if (!QFileInfo(basePath).exists()) {
1157 filename = url;
1158 } else {
1159 QDir d(basePath);
1160 filename = d.relativeFilePath(url);
1161 }
1162 }
1163 }
1164
1165 KisLayer *layer = new KisFileLayer(image, basePath, filename, (KisFileLayer::ScalingMethod)scalingMethod, scalingFilter, name, opacity, fallbackColorSpace);
1166 Q_CHECK_PTR(layer);
1167
1168 return layer;
1169}
1170
1171KisNodeSP KisKraLoader::loadGroupLayer(const QDomElement& element, KisImageSP image,
1172 const QString& name, const KoColorSpace* cs, quint32 opacity)
1173{
1174 Q_UNUSED(element);
1175 KisGroupLayer* layer;
1176
1177 layer = new KisGroupLayer(image, name, opacity, cs);
1178 Q_CHECK_PTR(layer);
1179
1180 return layer;
1181
1182}
1183
1185 const QString& name, const KoColorSpace* cs, quint32 opacity)
1186{
1187 // XXX: do something with filterversion?
1188 Q_UNUSED(cs);
1189 QString attr;
1190 KisAdjustmentLayer* layer;
1191 QString filtername;
1192 QString legacy = filtername;
1193
1194 if ((filtername = element.attribute(FILTER_NAME)).isNull()) {
1195 // XXX: Invalid adjustment layer! We should warn about it!
1196 warnFile << "No filter in adjustment layer";
1197 return 0;
1198 }
1199
1200 //get deprecated filters.
1201 if (filtername=="brightnesscontrast") {
1202 legacy = filtername;
1203 filtername = "perchannel";
1204 }
1205 if (filtername=="left edge detections"
1206 || filtername=="right edge detections"
1207 || filtername=="top edge detections"
1208 || filtername=="bottom edge detections") {
1209 legacy = filtername;
1210 filtername = "edge detection";
1211 }
1212
1214 if (!f) {
1215 warnFile << "No filter for filtername" << filtername << "";
1216 return 0; // XXX: We don't have this filter. We should warn about it!
1217 }
1218
1219 KisFilterConfigurationSP kfc = f->defaultConfiguration(KisGlobalResourcesInterface::instance());
1220 kfc->createLocalResourcesSnapshot();
1221 kfc->setProperty("legacy", legacy);
1222 if (legacy=="brightnesscontrast") {
1223 kfc->setProperty("colorModel", cs->colorModelId().id());
1224 }
1225
1226 // We'll load the configuration and the selection later.
1227 layer = new KisAdjustmentLayer(image, name, kfc, 0);
1228 Q_CHECK_PTR(layer);
1229
1230 layer->setOpacity(opacity);
1231
1232 return layer;
1233
1234}
1235
1236
1237KisNodeSP KisKraLoader::loadShapeLayer(const QDomElement& element, KisImageSP image,
1238 const QString& name, const KoColorSpace* cs, quint32 opacity)
1239{
1240
1241 Q_UNUSED(element);
1242 Q_UNUSED(cs);
1243
1244 QString attr;
1245 KoShapeControllerBase * shapeController = 0;
1246 if (m_d->document) {
1247 shapeController = m_d->document->shapeController();
1248 }
1249 KisShapeLayer* layer = new KisShapeLayer(shapeController, image, name, opacity);
1250 Q_CHECK_PTR(layer);
1251
1252 return layer;
1253
1254}
1255
1256
1258 const QString& name, const KoColorSpace* cs, quint32 opacity)
1259{
1260 Q_UNUSED(cs);
1261 // XXX: do something with generator version?
1262 KisGeneratorLayer* layer;
1263 QString generatorname = element.attribute(GENERATOR_NAME);
1264
1265 if (generatorname.isNull()) {
1266 // XXX: Invalid generator layer! We should warn about it!
1267 warnFile << "No generator in generator layer";
1268 return 0;
1269 }
1270
1271 KisGeneratorSP generator = KisGeneratorRegistry::instance()->value(generatorname);
1272 if (!generator) {
1273 warnFile << "No generator for generatorname" << generatorname << "";
1274 return 0; // XXX: We don't have this generator. We should warn about it!
1275 }
1276
1278 kgc->createLocalResourcesSnapshot();
1279
1280 // We'll load the configuration and the selection later.
1281 layer = new KisGeneratorLayer(image, name, kgc, 0);
1282 Q_CHECK_PTR(layer);
1283
1284 layer->setOpacity(opacity);
1285
1286 return layer;
1287
1288}
1289
1290KisNodeSP KisKraLoader::loadCloneLayer(const QDomElement& element, KisImageSP image,
1291 const QString& name, const KoColorSpace* cs, quint32 opacity)
1292{
1293 Q_UNUSED(cs);
1294
1295 KisCloneLayerSP layer = new KisCloneLayer(0, image, name, opacity);
1296
1297 KisNodeUuidInfo info;
1298 if (! (element.attribute(CLONE_FROM_UUID)).isNull()) {
1299 info = KisNodeUuidInfo(QUuid(element.attribute(CLONE_FROM_UUID)));
1300 } else {
1301 if ((element.attribute(CLONE_FROM)).isNull()) {
1302 return 0;
1303 } else {
1304 info = KisNodeUuidInfo(element.attribute(CLONE_FROM));
1305 }
1306 }
1307 layer->setCopyFromInfo(info);
1308
1309 if ((element.attribute(CLONE_TYPE)).isNull()) {
1310 return 0;
1311 } else {
1312 layer->setCopyType((CopyLayerType) element.attribute(CLONE_TYPE).toInt());
1313 }
1314
1315 return layer;
1316}
1317
1318
1319KisNodeSP KisKraLoader::loadFilterMask(KisImageSP image, const QDomElement& element)
1320{
1321 QString attr;
1322 KisFilterMask* mask;
1323 QString filtername;
1324
1325 // XXX: should we check the version?
1326
1327 if ((filtername = element.attribute(FILTER_NAME)).isNull()) {
1328 // XXX: Invalid filter layer! We should warn about it!
1329 warnFile << "No filter in filter layer";
1330 return 0;
1331 }
1332
1334 if (!f) {
1335 warnFile << "No filter for filtername" << filtername << "";
1336 return 0; // XXX: We don't have this filter. We should warn about it!
1337 }
1338
1339 KisFilterConfigurationSP kfc = f->defaultConfiguration(KisGlobalResourcesInterface::instance());
1340 kfc->createLocalResourcesSnapshot();
1341
1342 // We'll load the configuration and the selection later.
1343 mask = new KisFilterMask(image);
1344 mask->setFilter(kfc);
1345 Q_CHECK_PTR(mask);
1346
1347 return mask;
1348}
1349
1350KisNodeSP KisKraLoader::loadTransformMask(KisImageSP image, const QDomElement& element)
1351{
1352 Q_UNUSED(element);
1353
1354 KisTransformMask* mask;
1355
1360 mask = new KisTransformMask(image, "");
1361 Q_CHECK_PTR(mask);
1362
1363 return mask;
1364}
1365
1367{
1368 Q_UNUSED(element);
1369 KisTransparencyMask* mask = new KisTransparencyMask(image, "");
1370 Q_CHECK_PTR(mask);
1371
1372 return mask;
1373}
1374
1375KisNodeSP KisKraLoader::loadSelectionMask(KisImageSP image, const QDomElement& element)
1376{
1377 KisSelectionMaskSP mask = new KisSelectionMask(image);
1378 bool active = element.attribute(ACTIVE, "1") == "0" ? false : true;
1379 mask->setActive(active);
1380 Q_CHECK_PTR(mask);
1381
1382 return mask;
1383}
1384
1385KisNodeSP KisKraLoader::loadColorizeMask(KisImageSP image, const QDomElement& element, const KoColorSpace *colorSpace)
1386{
1387 KisColorizeMaskSP mask = new KisColorizeMask(image, "");
1388 const bool editKeystrokes = element.attribute(COLORIZE_EDIT_KEYSTROKES, "1") == "0" ? false : true;
1389 const bool showColoring = element.attribute(COLORIZE_SHOW_COLORING, "1") == "0" ? false : true;
1390
1394 mask->setSectionModelProperties(props);
1395
1396 const bool useEdgeDetection = KisDomUtils::toInt(element.attribute(COLORIZE_USE_EDGE_DETECTION, "0"));
1397 const qreal edgeDetectionSize = KisDomUtils::toDouble(element.attribute(COLORIZE_EDGE_DETECTION_SIZE, "4"));
1398 const qreal radius = KisDomUtils::toDouble(element.attribute(COLORIZE_FUZZY_RADIUS, "0"));
1399 const int cleanUp = KisDomUtils::toInt(element.attribute(COLORIZE_CLEANUP, "0"));
1400 const bool limitToDevice = KisDomUtils::toInt(element.attribute(COLORIZE_LIMIT_TO_DEVICE, "0"));
1401
1402 mask->setUseEdgeDetection(useEdgeDetection);
1403 mask->setEdgeDetectionSize(edgeDetectionSize);
1404 mask->setFuzzyRadius(radius);
1405 mask->setCleanUpAmount(qreal(cleanUp) / 100.0);
1406 mask->setLimitToDeviceBounds(limitToDevice);
1407
1408 delete mask->setColorSpace(colorSpace);
1409
1410 return mask;
1411}
1412
1413void KisKraLoader::loadCompositions(const QDomElement& elem, KisImageSP image)
1414{
1415 QDomNode child;
1416
1417 for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) {
1418
1419 QDomElement e = child.toElement();
1420 QString name = e.attribute("name");
1421 bool exportEnabled = e.attribute("exportEnabled", "1") == "0" ? false : true;
1422
1423 KisLayerCompositionSP composition(new KisLayerComposition(image, name));
1424 composition->setExportEnabled(exportEnabled);
1425
1426 QDomNode value;
1427 for (value = child.lastChild(); !value.isNull(); value = value.previousSibling()) {
1428 QDomElement e = value.toElement();
1429 QUuid uuid(e.attribute("uuid"));
1430 bool visible = e.attribute("visible", "1") == "0" ? false : true;
1431 composition->setVisible(uuid, visible);
1432 bool collapsed = e.attribute("collapsed", "1") == "0" ? false : true;
1433 composition->setCollapsed(uuid, collapsed);
1434 }
1435
1436 image->addComposition(composition);
1437 }
1438}
1439
1440void KisKraLoader::loadAssistantsList(const QDomElement &elem)
1441{
1442 QDomNode child;
1443 int count = 0;
1444 for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) {
1445 QDomElement e = child.toElement();
1446 QString type = e.attribute("type");
1447 QString file_name = e.attribute("filename");
1448 m_d->assistantsFilenames.insert(file_name,type);
1449 count++;
1450
1451 }
1452}
1453
1454void KisKraLoader::loadGrid(const QDomElement& elem)
1455{
1456 QDomDocument dom;
1457 dom.appendChild(dom.importNode(elem, true));
1458 QDomElement domElement = dom.firstChildElement();
1459
1460 KisGridConfig config;
1461 config.loadStaticData();
1462 config.loadDynamicDataFromXml(domElement);
1463 m_d->document->setGridConfig(config);
1464}
1465
1466void KisKraLoader::loadGuides(const QDomElement& elem)
1467{
1468 QDomDocument dom;
1469 dom.appendChild(dom.importNode(elem, true));
1470 QDomElement domElement = dom.firstChildElement();
1471
1472 KisGuidesConfig guides;
1473 guides.loadFromXml(domElement);
1474 m_d->document->setGuidesConfig(guides);
1475}
1476
1477void KisKraLoader::loadMirrorAxis(const QDomElement &elem)
1478{
1479 QDomDocument dom;
1480 dom.appendChild(dom.importNode(elem, true));
1481 QDomElement domElement = dom.firstChildElement();
1482
1483 KisMirrorAxisConfig mirrorAxis;
1484 mirrorAxis.loadFromXml(domElement);
1485 m_d->document->setMirrorAxisConfig(mirrorAxis);
1486}
1487
1488void KisKraLoader::loadStoryboardItemList(const QDomElement& elem)
1489{
1490 QDomNode child;
1491 int count = 0;
1492 for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) {
1493 QDomElement e = child.toElement();
1494 if (e.tagName() == "storyboarditem") {
1496 item->loadXML(e);
1497 count++;
1498 m_d->storyboardItemList.append(item);
1499 }
1500 }
1501}
1502
1503void KisKraLoader::loadStoryboardCommentList(const QDomElement& elem)
1504{
1505 QDomNode child;
1506 int count = 0;
1507 for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) {
1508 QDomElement e = child.toElement();
1509 if (e.tagName() == "storyboardcomment") {
1510 StoryboardComment comment;
1511 if (e.hasAttribute("visibility")) {
1512 comment.visibility = e.attribute("visibility").toInt();
1513 }
1514 if (e.hasAttribute("name")) {
1515 comment.name = e.attribute("name");
1516 }
1517 count++;
1518 m_d->storyboardCommentList.append(comment);
1519 }
1520 }
1521}
1522
1523void KisKraLoader::loadAudioXML(QDomDocument &xmlDoc, QDomElement &xmlElement, KisDocument *kisDoc)
1524{
1525 Q_UNUSED(xmlDoc);
1526 QDomNode audioClip = xmlElement.firstChild();
1527 if (audioClip.nodeName() == "audioClips") {
1528 QDomElement audioClipElement = audioClip.toElement();
1529 QVector<QFileInfo> clipFiles;
1530 qreal volume = 1.0;
1531 QDomNode clip;
1532 for (clip = audioClipElement.firstChild(); !clip.isNull(); clip = clip.nextSibling()) {
1533 QDomElement clipElem = clip.toElement();
1534
1535 if (clipElem.hasAttribute("filePath")) {
1536 QFileInfo f(clipElem.attribute("filePath"));
1537 if (f.exists()) {
1538 clipFiles << f;
1539 }
1540 }
1541
1542 if (clipElem.hasAttribute("volume")) {
1543 volume = clipElem.attribute("volume").toDouble();
1544 }
1545 }
1546
1547 kisDoc->setAudioTracks(clipFiles);
1548 kisDoc->setAudioVolume(volume);
1549 }
1550}
1551
1553{
1556
1557 m_d->document->setReferenceImagesLayer(layer, false);
1558
1559 for (QDomElement child = elem.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) {
1560 if (child.nodeName().toLower() == "referenceimage") {
1561 auto* reference = KisReferenceImage::fromXml(child);
1562 reference->setZIndex(layer->shapes().size());
1563 layer->addShape(reference);
1564 }
1565 }
1566
1567 return layer;
1568}
1569
1570QList<KoColor> KisKraLoader::loadKoColors(const QDomElement &colorElement) const
1571{
1572 QList<KoColor> colors;
1573 QDomNodeList colorNodes = colorElement.childNodes();
1574 colors.reserve(colorNodes.size());
1575
1576 for (int k = 0; k < colorNodes.size(); k++) {
1577 QDomElement colorElement = colorNodes.at(k).toElement();
1578 KoColor color = KoColor::fromXML(colorElement, Integer16BitsColorDepthID.id());
1579 colors.push_back(color);
1580 }
1581
1582 return colors;
1583}
float value(const T *src, size_t ch)
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID CMYKAColorModelID("CMYKA", ki18n("CMYK/Alpha"))
QStringList subtractiveBlendingModesInCmyk()
the list of blendmodes that perform channel-inversion in CMYK color space
const quint8 OPACITY_TRANSPARENT_U8
const quint8 OPACITY_OPAQUE_U8
const QString DESCRIPTION
char nodeType(const KoPathPoint *point)
A data extension mechanism for Krita.
void assignAllLayerStylesToLayers(KisNodeSP root, const QString &storageLocation)
KisBaseNode::PropertyList sectionModelProperties() const override
void setEdgeDetectionSize(qreal value)
void setLimitToDeviceBounds(bool value)
void setSectionModelProperties(const KisBaseNode::PropertyList &properties) override
void setUseEdgeDetection(bool value)
void setFuzzyRadius(qreal value)
KUndo2Command * setColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KoUpdater *progressUpdater=nullptr)
void setCleanUpAmount(qreal value)
The KisCursorOverrideHijacker class stores all override cursors in a stack, and resets them back afte...
KisUndoStore * createUndoStore()
KoDocumentInfo * documentInfo() const
KisImageSP image
QString linkedResourcesStorageId() const
KisShapeController * shapeController
void setAudioTracks(QVector< QFileInfo > f)
QString localFilePath() const
void setMirrorAxisConfig(const KisMirrorAxisConfig &config)
void setAssistantsGlobalColor(QColor color)
void setReferenceImagesLayer(KisSharedPtr< KisReferenceImagesLayer > layer, bool updateImage)
QString path() const
QColor assistantsGlobalColor()
QString embeddedResourcesStorageId() const
void setGridConfig(const KisGridConfig &config)
void setAudioVolume(qreal level)
void setGuidesConfig(const KisGuidesConfig &data)
void setPaletteList(const QList< KoColorSetSP > &paletteList, bool emitSignal=false)
setPaletteList replaces the palettes in the document's local resource storage with the list of palett...
void setColorHistory(const QList< KoColor > &colors)
The KisFileLayer class loads a particular file as a layer into the layer stack.
void setFilter(KisFilterConfigurationSP filterConfig, bool checkCompareConfig=true) override
static KisFilterRegistry * instance()
static KisGeneratorRegistry * instance()
static KisResourcesInterfaceSP instance()
bool loadDynamicDataFromXml(const QDomElement &parent)
bool loadFromXml(const QDomElement &parent)
void setExportSequenceBaseName(const QString &baseName)
void switchCurrentTimeAsync(int frameId, SwitchTimeAsyncFlags options=STAO_NONE)
void setDocumentRange(const KisTimeSpan range)
void setExportInitialFrameNumber(const int frameNum)
void setExportSequenceFilePath(const QString &filePath)
KisProofingConfigurationSP defaultProofingconfiguration(bool requestDefault=false)
void addAnnotation(KisAnnotationSP annotation)
KisGroupLayerSP rootLayer() const
const KoColorSpace * colorSpace() const
KisImageAnimationInterface * animationInterface() const
void setDefaultProjectionColor(const KoColor &color)
void setProofingConfiguration(KisProofingConfigurationSP proofingConfig)
setProofingConfiguration, this sets the image's proofing configuration, and signals the proofingConfi...
void addComposition(KisLayerCompositionSP composition)
void setResolution(double xres, double yres)
void convertImageProjectionColorSpace(const KoColorSpace *dstColorSpace)
KisProofingConfigurationSP proofingConfiguration() const
proofingConfiguration
static QString askForAudioFileName(const QString &defaultDir, QWidget *parent)
static QStringList supportedMimeTypes(Direction direction)
void setExternalUri(const QString &uri)
QStringList warningMessages() const
QStringList errorMessages() const
KisNodeSP loadFilterMask(KisImageSP image, const QDomElement &elem)
KisImageSP loadXML(const QDomElement &imageElement)
KisNodeSP loadNodes(const QDomElement &element, KisImageSP image, KisNodeSP parent)
void loadAnimationMetadata(KoStore *store, KisImageSP image)
KisNodeSP loadFileLayer(const QDomElement &elem, KisImageSP image, const QString &name, quint32 opacity, const KoColorSpace *fallbackColorSpace)
KisNodeSP loadShapeLayer(const QDomElement &elem, KisImageSP image, const QString &name, const KoColorSpace *cs, quint32 opacity)
void loadAudioXML(QDomDocument &xmlDoc, QDomElement &xmlElement, KisDocument *kisDoc)
void loadCompositions(const QDomElement &elem, KisImageSP image)
KisNodeSP loadColorizeMask(KisImageSP image, const QDomElement &elem, const KoColorSpace *colorSpace)
void loadAssistantsList(const QDomElement &elem)
void loadStoryboardItemList(const QDomElement &elem)
QStringList errorMessages() const
if empty, loading didn't fail...
KisNodeSP loadCloneLayer(const QDomElement &elem, KisImageSP image, const QString &name, const KoColorSpace *cs, quint32 opacity)
KisNodeSP loadGeneratorLayer(const QDomElement &elem, KisImageSP image, const QString &name, const KoColorSpace *cs, quint32 opacity)
void loadStoryboards(KoStore *store, KisDocument *doc)
KisNodeSP loadPaintLayer(const QDomElement &elem, KisImageSP image, const QString &name, const KoColorSpace *cs, quint32 opacity)
QString imageName() const
QStringList warningMessages() const
if not empty, loading didn't fail, but there are problems
void loadGuides(const QDomElement &elem)
void loadGrid(const QDomElement &elem)
KisNodeSP loadNode(const QDomElement &elem, KisImageSP image)
KisKraLoader(KisDocument *document, int syntaxVersion, const QVersionNumber &kritaVersion)
void loadBinaryData(KoStore *store, KisImageSP image, const QString &uri, bool external)
vKisNodeSP selectedNodes() const
void loadResources(KoStore *store, KisDocument *doc)
void loadMirrorAxis(const QDomElement &elem)
void loadAnimationMetadataFromXML(const QDomElement &element, KisImageSP image)
void loadStoryboardCommentList(const QDomElement &elem)
Q_DECL_DEPRECATED void backCompat_loadAudio(const QDomElement &elem, KisImageSP image, KisDocument *document)
KisNodeSP loadSelectionMask(KisImageSP image, const QDomElement &elem)
StoryboardItemList storyboardItemList() const
KisNodeSP loadTransformMask(KisImageSP image, const QDomElement &elem)
Private *const m_d
KisNodeSP loadGroupLayer(const QDomElement &elem, KisImageSP image, const QString &name, const KoColorSpace *cs, quint32 opacity)
QList< KoColor > loadKoColors(const QDomElement &elem) const
KisNodeSP loadReferenceImagesLayer(const QDomElement &elem, KisImageSP image)
KisNodeSP loadTransparencyMask(KisImageSP image, const QDomElement &elem)
void loadAssistants(KoStore *store, const QString &uri, bool external)
QList< KisPaintingAssistantSP > assistants() const
StoryboardCommentList storyboardCommentList() const
KisNodeSP loadAdjustmentLayer(const QDomElement &elem, KisImageSP image, const QString &name, const KoColorSpace *cs, quint32 opacity)
void loadAudio(KoStore *store, KisDocument *kisDoc)
static void setNodeProperty(KisBaseNode::PropertyList *props, const KoID &id, const QVariant &value)
The KisMirrorAxisConfig class stores configuration for the KisMirrorAxis canvas decoration....
bool loadFromXml(const QDomElement &parent)
loadFromXml() function for KisKraLoader
static KisNodeViewColorScheme * instance()
QVector< QColor > allColorLabels() const
static KisPaintingAssistantFactoryRegistry * instance()
virtual KisPaintingAssistant * createPaintingAssistant() const =0
void setAssistantGlobalColorCache(const QColor &color)
virtual int numHandles() const =0
void loadXml(KoStore *store, QMap< int, KisPaintingAssistantHandleSP > &handleMap, QString path)
const QList< KisPaintingAssistantHandleSP > & handles() const
@ Custom
Let artists configure their own.
@ Paper
Whether to use Paper settings (absolute colorimetric, 0% adaptation.)
@ Monitor
Whether to use monitor rendering intent and flags for the second transform.
static KisReferenceImage * fromXml(const QDomElement &elem)
The KisResourceModel class provides the main access to resources. It is possible to filter the resour...
QVector< KoResourceSP > resourcesForMD5(const QString md5sum) const
KoResourceSP importResource(const QString &filename, QIODevice *device, const bool allowOverwrite, const QString &storageId=QString("")) override
importResource imports a resource from a QIODevice
void setAntialiased(const bool antialiased)
virtual KoID colorModelId() const =0
virtual quint32 channelCount() const =0
virtual KoID colorDepthId() const =0
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
Definition KoColor.cpp:350
static const KoCompositeOpRegistry & instance()
void setAboutInfo(const QString &info, const QString &data)
QString aboutInfo(const QString &info) const
const T value(const QString &id) const
T get(const QString &id) const
QString id() const
Definition KoID.cpp:63
A simple wrapper object for the main information about the resource.
void close() override
bool open(OpenMode m) override
QIODevice * device() const
Definition KoStore.cpp:171
bool close()
Definition KoStore.cpp:156
qint64 size() const
Definition KoStore.cpp:239
bool isOpen() const
Definition KoStore.cpp:150
bool hasFile(const QString &fileName) const
Definition KoStore.cpp:384
bool open(const QString &name)
Definition KoStore.cpp:109
QByteArray read(qint64 max)
Definition KoStore.cpp:181
This class stores a list of StoryboardChild objects and provides functionality to manipulate the list...
This file is part of the Krita application in calligra.
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
CopyLayerType
#define warnFile
Definition kis_debug.h:95
#define warnKrita
Definition kis_debug.h:87
#define dbgFile
Definition kis_debug.h:53
void convertColorSpaceNames(QString &colorspacename, QString &profileProductName)
QSharedPointer< T > toQShared(T *ptr)
KisSharedPtr< KisAnnotation > KisAnnotationSP
Definition kis_types.h:179
KisSharedPtr< KisImage > KisImageSP
Definition kis_types.h:69
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 PALETTES
const QString PROOFINGPROFILENAME
const QString COLORHISTORY
const QString CANVASPROJECTIONCOLOR
const QString CLONE_FROM
const QString CLONE_TYPE
const QString CLONE_FROM_UUID
const QString COLORBYTEDATA
const QString PROOFINGBLACKPOINTCOMPENSATION
const QString NAME
const QString ICC_PROOFING_PATH
const QString VISIBLE
const QString COLORIZE_EDIT_KEYSTROKES
const QString Y_RESOLUTION
const QString HEIGHT
const QString ASSISTANTS_PATH
const QString FILE_LAYER
const QString COLOR_LABEL
const QString OPACITY
const QString PROOFINGDEPTH
const QString ANIMATION_METADATA_PATH
const QString NATIVE_MIMETYPE
const QString LAYER_STYLES_PATH
const QString X_RESOLUTION
const QString STORYBOARD_PATH
const QString X
const QString RESOURCES
const QString FILE_NAME
const QString ANNOTATIONS_PATH
const QString PROOFINGDISPLAYBLACKPOINTCOMPENSATION
const QString PASS_THROUGH_MODE
const QString COLORIZE_EDGE_DETECTION_SIZE
const QString PROOFINGDISPLAYMODE
const QString COMPOSITE_OP
const QString ICC_PATH
const QString PROOFINGWARNINGCOLOR
const QString KEYFRAME_FILE
const QString PAINT_LAYER
const QString PROOFINGDISPLAYINTENT
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 WIDTH
const QString EXIF_PATH
const QString MIME
const QString CHANNEL_LOCK_FLAGS
const QString GLOBALASSISTANTSCOLOR
const QString COLLAPSED
const QString ANNOTATIONS
const QString TRANSFORM_MASK
const QString COLORIZE_SHOW_COLORING
const QString ONION_SKIN_ENABLED
const QString RESOURCE_PATH
const QString LAYERS
const QString PROOFINGMODEL
const QString AUDIO_PATH
const QString REFERENCE_IMAGES_LAYER
const QString COLORIZE_USE_EDGE_DETECTION
const QString PALETTE_PATH
const QString PROOFINGINTENT
const QString ANTIALIASED
const QString FILTER_MASK
const QString ACTIVE
const QString MIRROR_AXIS
const QString SIMPLECOLORDATA
const QString UUID
const QString PROOFINGADAPTATIONSTATE
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
QColor qStringToQColor(QString colorString)
double toDouble(const QString &str, bool *ok=nullptr)
int toInt(const QString &str, bool *ok=nullptr)
void setPinnedToTimeline(bool pinned)
virtual void setUserLocked(bool l)
void setOpacity(quint8 val)
virtual void setVisible(bool visible, bool loading=false)
virtual void setX(qint32)
void setUuid(const QUuid &id)
virtual void setY(qint32)
void setColorLabelIndex(int index)
void setName(const QString &name)
void setCollapsed(bool collapsed)
QString name() const
void setCompositeOpId(const QString &compositeOpId)
virtual KisFilterConfigurationSP defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const
bool accept(KisNodeVisitor &v) override
void setPassThroughMode(bool value)
StoryboardCommentList storyboardCommentList
QList< KisPaintingAssistantSP > assistants
QMap< KisNode *, QString > keyframeFilenames
QVersionNumber kritaVersion
QVector< QString > paletteFilenames
QMap< KisNode *, QString > layerFilenames
StoryboardItemList storyboardItemList
QList< KisAnnotationSP > annotations
QVector< KoResourceSignature > resources
QMap< QString, QString > assistantsFilenames
virtual void setChannelFlags(const QBitArray &channelFlags)
Definition kis_layer.cc:342
void setLayerStyle(KisPSDLayerStyleSP layerStyle)
Definition kis_layer.cc:254
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
QList< KisNodeSP > childNodes(const QStringList &nodeTypes, const KoProperties &properties) const
Definition kis_node.cpp:439
quint32 childCount() const
Definition kis_node.cpp:414
The KisPSDLayerStyle class implements loading, saving and applying the PSD layer effects.
void setChannelLockFlags(const QBitArray &channelFlags)
void setOnionSkinEnabled(bool state)
void setActive(bool active)
virtual bool valid() const =0
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
KoID colorSpaceColorDepthId(const QString &_colorSpaceId) const
KoID colorSpaceColorModelId(const QString &_colorSpaceId) const
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)
void addProfile(KoColorProfile *profile)