File indexing completed on 2024-12-22 04:15:47

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "kis_kra_loader.h"
0008 
0009 #include <QApplication>
0010 #include <QStringList>
0011 
0012 #include <QMessageBox>
0013 
0014 #include <QUrl>
0015 #include <QBuffer>
0016 #include <QVersionNumber>
0017 
0018 #include <KoStore.h>
0019 #include <KoColorSpaceRegistry.h>
0020 #include <KoColorSpaceEngine.h>
0021 #include <KoColorProfile.h>
0022 #include <KoDocumentInfo.h>
0023 #include <KoFileDialog.h>
0024 #include <KisImportExportManager.h>
0025 #include <KoStoreDevice.h>
0026 #include <KisResourceServerProvider.h>
0027 #include <KoResourceServer.h>
0028 #include <KisResourceStorage.h>
0029 #include <KisGlobalResourcesInterface.h>
0030 #include <KisResourceModel.h>
0031 
0032 #include <filter/kis_filter.h>
0033 #include <filter/kis_filter_registry.h>
0034 #include <generator/kis_generator.h>
0035 #include <generator/kis_generator_layer.h>
0036 #include <generator/kis_generator_registry.h>
0037 #include <kis_adjustment_layer.h>
0038 #include <kis_annotation.h>
0039 #include <kis_base_node.h>
0040 #include <kis_clone_layer.h>
0041 #include <kis_debug.h>
0042 #include <kis_assert.h>
0043 #include <kis_external_layer_iface.h>
0044 #include <kis_filter_mask.h>
0045 #include <kis_transform_mask.h>
0046 #include "lazybrush/kis_colorize_mask.h"
0047 #include <kis_group_layer.h>
0048 #include <kis_image.h>
0049 #include <kis_layer.h>
0050 #include <kis_name_server.h>
0051 #include <kis_paint_layer.h>
0052 #include <kis_selection.h>
0053 #include <kis_selection_mask.h>
0054 #include <kis_shape_layer.h>
0055 #include <kis_transparency_mask.h>
0056 #include <kis_layer_composition.h>
0057 #include <kis_file_layer.h>
0058 #include <kis_psd_layer_style.h>
0059 #include <kis_asl_layer_style_serializer.h>
0060 #include "kis_keyframe_channel.h"
0061 #include <kis_filter_configuration.h>
0062 #include "KisReferenceImagesLayer.h"
0063 #include "KisReferenceImage.h"
0064 #include <KoColorSet.h>
0065 
0066 #include "KisDocument.h"
0067 #include "kis_config.h"
0068 #include "kis_kra_tags.h"
0069 #include "kis_kra_utils.h"
0070 #include "kis_kra_load_visitor.h"
0071 #include "kis_dom_utils.h"
0072 #include "kis_image_animation_interface.h"
0073 #include "kis_time_span.h"
0074 #include "kis_grid_config.h"
0075 #include "kis_guides_config.h"
0076 #include "kis_image_config.h"
0077 #include "KisProofingConfiguration.h"
0078 #include "kis_layer_properties_icons.h"
0079 #include "kis_node_view_color_scheme.h"
0080 #include "KisMirrorAxisConfig.h"
0081 #include <kis_cursor_override_hijacker.h>
0082 
0083 /*
0084   Color model id comparison through the ages:
0085 
0086 2.4        2.5          2.6         ideal
0087 
0088 ALPHA      ALPHA        ALPHA       ALPHAU8
0089 
0090 CMYK       CMYK         CMYK        CMYKAU8
0091            CMYKAF32     CMYKAF32
0092 CMYKA16    CMYKAU16     CMYKAU16
0093 
0094 GRAYA      GRAYA        GRAYA       GRAYAU8
0095 GrayF32    GRAYAF32     GRAYAF32
0096 GRAYA16    GRAYAU16     GRAYAU16
0097 
0098 LABA       LABA         LABA        LABAU16
0099            LABAF32      LABAF32
0100            LABAU8       LABAU8
0101 
0102 RGBA       RGBA         RGBA        RGBAU8
0103 RGBA16     RGBA16       RGBA16      RGBAU16
0104 RgbAF32    RGBAF32      RGBAF32
0105 RgbAF16    RgbAF16      RGBAF16
0106 
0107 XYZA16     XYZA16       XYZA16      XYZAU16
0108            XYZA8        XYZA8       XYZAU8
0109 XyzAF16    XyzAF16      XYZAF16
0110 XyzAF32    XYZAF32      XYZAF32
0111 
0112 YCbCrA     YCBCRA8      YCBCRA8     YCBCRAU8
0113 YCbCrAU16  YCBCRAU16    YCBCRAU16
0114            YCBCRF32     YCBCRF32
0115  */
0116 
0117 using namespace KRA;
0118 
0119 struct KisKraLoader::Private
0120 {
0121 public:
0122     KisDocument* document;
0123     QString imageName; // used to be stored in the image, is now in the documentInfo block
0124     QString imageComment; // used to be stored in the image, is now in the documentInfo block
0125     QMap<KisNode*, QString> layerFilenames; // temp storage during loading
0126     int syntaxVersion; // version of the fileformat we are loading
0127     QVersionNumber kritaVersion;
0128     vKisNodeSP selectedNodes; // the nodes that were active when saving the document.
0129     QMap<QString, QString> assistantsFilenames;
0130     StoryboardItemList storyboardItemList;
0131     StoryboardCommentList storyboardCommentList;
0132     QList<KisPaintingAssistantSP> assistants;
0133     QMap<KisNode*, QString> keyframeFilenames;
0134     QVector<QString> paletteFilenames;
0135     QVector<KoResourceSignature> resources;
0136     QStringList errorMessages;
0137     QStringList warningMessages;
0138     QList<KisAnnotationSP> annotations;
0139 };
0140 
0141 void convertColorSpaceNames(QString &colorspacename, QString &profileProductName) {
0142     if (colorspacename  == "Grayscale + Alpha") {
0143         colorspacename  = "GRAYA";
0144         profileProductName.clear();
0145     }
0146     else if (colorspacename == "RgbAF32") {
0147         colorspacename = "RGBAF32";
0148         profileProductName.clear();
0149     }
0150     else if (colorspacename == "RgbAF16") {
0151         colorspacename = "RGBAF16";
0152         profileProductName.clear();
0153     }
0154     else if (colorspacename == "CMYKA16") {
0155         colorspacename = "CMYKAU16";
0156     }
0157     else if (colorspacename == "GrayF32") {
0158         colorspacename =  "GRAYAF32";
0159         profileProductName.clear();
0160     }
0161     else if (colorspacename == "GRAYA16") {
0162         colorspacename  = "GRAYAU16";
0163     }
0164     else if (colorspacename == "XyzAF16") {
0165         colorspacename  = "XYZAF16";
0166         profileProductName.clear();
0167     }
0168     else if (colorspacename == "XyzAF32") {
0169         colorspacename  = "XYZAF32";
0170         profileProductName.clear();
0171     }
0172     else if (colorspacename == "YCbCrA") {
0173         colorspacename  = "YCBCRA8";
0174     }
0175     else if (colorspacename == "YCbCrAU16") {
0176         colorspacename  = "YCBCRAU16";
0177     }
0178 }
0179 
0180 KisKraLoader::KisKraLoader(KisDocument * document, int syntaxVersion, const QVersionNumber &kritaVersion)
0181     : m_d(new Private())
0182 {
0183     m_d->document = document;
0184     m_d->syntaxVersion = syntaxVersion;
0185     m_d->kritaVersion = kritaVersion;
0186 }
0187 
0188 
0189 KisKraLoader::~KisKraLoader()
0190 {
0191     delete m_d;
0192 }
0193 
0194 
0195 KisImageSP KisKraLoader::loadXML(const QDomElement& imageElement)
0196 {
0197     QString attr;
0198     KisImageSP image = 0;
0199     qint32 width;
0200     qint32 height;
0201     QString profileProductName;
0202     double xres;
0203     double yres;
0204     QString colorspacename;
0205     const KoColorSpace * cs;
0206 
0207     if ((attr = imageElement.attribute(MIME)) == NATIVE_MIMETYPE) {
0208 
0209         if ((m_d->imageName = imageElement.attribute(NAME)).isNull()) {
0210             m_d->errorMessages << i18n("Image does not have a name.");
0211             return KisImageSP(0);
0212         }
0213 
0214         if ((attr = imageElement.attribute(WIDTH)).isNull()) {
0215             m_d->errorMessages << i18n("Image does not specify a width.");
0216             return KisImageSP(0);
0217         }
0218         width = KisDomUtils::toInt(attr);
0219 
0220         if ((attr = imageElement.attribute(HEIGHT)).isNull()) {
0221             m_d->errorMessages << i18n("Image does not specify a height.");
0222             return KisImageSP(0);
0223         }
0224 
0225         height = KisDomUtils::toInt(attr);
0226 
0227         m_d->imageComment = imageElement.attribute(DESCRIPTION);
0228 
0229         xres = 100.0 / 72.0;
0230         if (!(attr = imageElement.attribute(X_RESOLUTION)).isNull()) {
0231             qreal value = KisDomUtils::toDouble(attr);
0232 
0233             if (value > 0) {
0234                 xres = value / 72.0;
0235             }
0236         }
0237 
0238         yres = 100.0 / 72.0;
0239         if (!(attr = imageElement.attribute(Y_RESOLUTION)).isNull()) {
0240             qreal value = KisDomUtils::toDouble(attr);
0241             if (value > 0) {
0242                 yres = value / 72.0;
0243             }
0244         }
0245 
0246         if ((colorspacename = imageElement.attribute(COLORSPACE_NAME)).isNull()) {
0247             // An old file: take a reasonable default.
0248             // Krita didn't support anything else in those
0249             // days anyway.
0250             colorspacename = "RGBA";
0251         }
0252 
0253         profileProductName = imageElement.attribute(PROFILE);
0254         // A hack for an old colorspacename
0255         convertColorSpaceNames(colorspacename, profileProductName);
0256 
0257         QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id();
0258         QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id();
0259 
0260         if (profileProductName.isNull()) {
0261             // no mention of profile so get default profile";
0262             cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, "");
0263         } else {
0264             cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, profileProductName);
0265         }
0266 
0267         if (cs == 0) {
0268             // try once more without the profile
0269             cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, "");
0270             if (cs == 0) {
0271                 m_d->errorMessages << i18n("Image specifies an unsupported color model: %1.", colorspacename);
0272                 return KisImageSP(0);
0273             }
0274         }
0275         KisProofingConfigurationSP proofingConfig = KisImageConfig(true).defaultProofingconfiguration();
0276         if (!(attr = imageElement.attribute(PROOFINGPROFILENAME)).isNull()) {
0277             proofingConfig->proofingProfile = attr;
0278             proofingConfig->storeSoftproofingInsideImage = true;
0279         }
0280         if (!(attr = imageElement.attribute(PROOFINGMODEL)).isNull()) {
0281             proofingConfig->proofingModel = attr;
0282         }
0283         if (!(attr = imageElement.attribute(PROOFINGDEPTH)).isNull()) {
0284             proofingConfig->proofingDepth = attr;
0285         }
0286         if (!(attr = imageElement.attribute(PROOFINGINTENT)).isNull()) {
0287             proofingConfig->intent = (KoColorConversionTransformation::Intent) KisDomUtils::toInt(attr);
0288         }
0289 
0290         if (!(attr = imageElement.attribute(PROOFINGADAPTATIONSTATE)).isNull()) {
0291             proofingConfig->adaptationState = KisDomUtils::toDouble(attr);
0292         }
0293 
0294         if (m_d->document) {
0295             image = new KisImage(m_d->document->createUndoStore(), width, height, cs, m_d->imageName);
0296         }
0297         else {
0298             image = new KisImage(0, width, height, cs, m_d->imageName);
0299         }
0300         image->setResolution(xres, yres);
0301         loadNodes(imageElement, image, const_cast<KisGroupLayer*>(image->rootLayer().data()));
0302 
0303 
0304         QDomNode child;
0305         for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
0306             QDomElement e = child.toElement();
0307 
0308             if(e.tagName() == CANVASPROJECTIONCOLOR) {
0309                 if (e.hasAttribute(COLORBYTEDATA)) {
0310                     QByteArray colorData = QByteArray::fromBase64(e.attribute(COLORBYTEDATA).toLatin1());
0311                     KoColor color((const quint8*)colorData.data(), image->colorSpace());
0312                     image->setDefaultProjectionColor(color);
0313                 }
0314             }
0315 
0316 
0317             if(e.tagName() == GLOBALASSISTANTSCOLOR) {
0318                 if (e.hasAttribute(SIMPLECOLORDATA)) {
0319                     QString colorData = e.attribute(SIMPLECOLORDATA);
0320                     m_d->document->setAssistantsGlobalColor(KisDomUtils::qStringToQColor(colorData));
0321                 }
0322             }
0323 
0324 
0325             if(e.tagName()== PROOFINGWARNINGCOLOR) {
0326                 QDomDocument dom;
0327                 QDomNode node = e;
0328                 dom.appendChild(dom.importNode(node, true));
0329                 QDomElement eq = dom.firstChildElement();
0330                 proofingConfig->warningColor = KoColor::fromXML(eq.firstChildElement(), Integer8BitsColorDepthID.id());
0331             }
0332 
0333             // COMPATIBILITY -- Load Animation Metadata from OLD KRA files.
0334             if (e.tagName().toLower() == "animation") {
0335                 loadAnimationMetadataFromXML(e, image);
0336             }
0337         }
0338 
0339         image->setProofingConfiguration(proofingConfig);
0340 
0341         for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
0342             QDomElement e = child.toElement();
0343             if (e.tagName() == "compositions") {
0344                 loadCompositions(e, image);
0345             }
0346         }
0347     }
0348 
0349     QDomNode child;
0350     for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
0351         QDomElement e = child.toElement();
0352         if (e.tagName() == "grid") {
0353             loadGrid(e);
0354         } else if (e.tagName() == "guides") {
0355             loadGuides(e);
0356         } else if (e.tagName() == MIRROR_AXIS) {
0357             loadMirrorAxis(e);
0358         } else if (e.tagName() == "assistants") {
0359             loadAssistantsList(e);
0360         } else if (e.tagName() == "audio") {
0361             backCompat_loadAudio(e, image, m_d->document);
0362         }
0363     }
0364 
0365     // reading palettes from XML
0366     for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
0367         QDomElement e = child.toElement();
0368         if (e.tagName() == PALETTES) {
0369             for (QDomElement paletteElement = e.lastChildElement(); !paletteElement.isNull();
0370                  paletteElement = paletteElement.previousSiblingElement()) {
0371                 QString paletteName = paletteElement.attribute("filename");
0372                 m_d->paletteFilenames.append(paletteName);
0373             }
0374             break;
0375         }
0376     }
0377 
0378     // reading resources from XML
0379     for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
0380         QDomElement e = child.toElement();
0381         if (e.tagName() == RESOURCES) {
0382             for (QDomElement resourceElement = e.lastChildElement();
0383                  !resourceElement.isNull();
0384                  resourceElement = resourceElement.previousSiblingElement())
0385             {
0386                 KoResourceSignature resourceItem;
0387                 resourceItem.filename = resourceElement.attribute("filename");
0388                 resourceItem.md5sum = resourceElement.attribute("md5sum");
0389                 resourceItem.type = resourceElement.attribute("type");
0390                 resourceItem.name = resourceElement.attribute("name");
0391                 m_d->resources.append(resourceItem);
0392             }
0393             break;
0394         }
0395     }
0396 
0397     // reading the extra annotations from XML
0398     for (child = imageElement.lastChild(); !child.isNull(); child = child.previousSibling()) {
0399         QDomElement e = child.toElement();
0400         if (e.tagName() == ANNOTATIONS) {
0401             for (QDomElement annotationElement = e.firstChildElement();
0402                  !annotationElement.isNull();
0403                  annotationElement = annotationElement.nextSiblingElement())
0404             {
0405                 QString type = annotationElement.attribute("type");
0406                 QString description = annotationElement.attribute("description");
0407 
0408                 KisAnnotationSP annotation = new KisAnnotation(type, description, QByteArray());
0409                 m_d->annotations << annotation;
0410             }
0411             break;
0412         }
0413     }
0414 
0415     return image;
0416 }
0417 
0418 void KisKraLoader::loadBinaryData(KoStore * store, KisImageSP image, const QString & uri, bool external)
0419 {
0420     // icc profile: if present, this overrides the profile product name loaded in loadXML.
0421     QString location = external ? QString() : uri;
0422     location += m_d->imageName + ICC_PATH;
0423     if (store->hasFile(location)) {
0424         if (store->open(location)) {
0425             QByteArray data; data.resize(store->size());
0426             bool res = (store->read(data.data(), store->size()) > -1);
0427             store->close();
0428             if (res) {
0429                 const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(image->colorSpace()->colorModelId().id(), image->colorSpace()->colorDepthId().id(), data);
0430                 if (profile && profile->valid()) {
0431                     res = image->assignImageProfile(profile, true);
0432                     image->waitForDone();
0433                 }
0434                 if (!res) {
0435                     const QString defaultProfileId = KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(image->colorSpace()->id());
0436                     profile = KoColorSpaceRegistry::instance()->profileByName(defaultProfileId);
0437                     Q_ASSERT(profile && profile->valid());
0438                     image->assignImageProfile(profile, true);
0439                     image->waitForDone();
0440                 }
0441             }
0442         }
0443     }
0444     //load the embed proofing profile, it only needs to be loaded into Krita, not assigned.
0445     location = external ? QString() : uri;
0446     location += m_d->imageName + ICC_PROOFING_PATH;
0447     if (store->hasFile(location)) {
0448         if (store->open(location)) {
0449             QByteArray proofingData;
0450             proofingData.resize(store->size());
0451             bool proofingProfileRes = (store->read(proofingData.data(), store->size())>-1);
0452             store->close();
0453 
0454             KisProofingConfigurationSP proofingConfig = image->proofingConfiguration();
0455             if (!proofingConfig) {
0456                 proofingConfig = KisImageConfig(true).defaultProofingconfiguration();
0457             }
0458 
0459             if (proofingProfileRes) {
0460                 const KoColorProfile *proofingProfile = KoColorSpaceRegistry::instance()->createColorProfile(proofingConfig->proofingModel, proofingConfig->proofingDepth, proofingData);
0461                 if (proofingProfile->valid()){
0462                     KoColorSpaceRegistry::instance()->addProfile(proofingProfile);
0463                 }
0464             }
0465         }
0466     }
0467 
0468 
0469     // Load the layers data: if there is a profile associated with a layer it will be set now.
0470     KisKraLoadVisitor visitor(image, store, m_d->document->shapeController(), m_d->layerFilenames, m_d->keyframeFilenames, m_d->imageName, m_d->syntaxVersion);
0471 
0472     if (external) {
0473         visitor.setExternalUri(uri);
0474     }
0475 
0476     image->rootLayer()->accept(visitor);
0477     if (!visitor.errorMessages().isEmpty()) {
0478         m_d->errorMessages.append(visitor.errorMessages());
0479     }
0480     if (!visitor.warningMessages().isEmpty()) {
0481         m_d->warningMessages.append(visitor.warningMessages());
0482     }
0483 
0484     // annotations
0485     // exif
0486     location = external ? QString() : uri;
0487     location += m_d->imageName + EXIF_PATH;
0488     if (store->hasFile(location)) {
0489         QByteArray data;
0490         store->open(location);
0491         data = store->read(store->size());
0492         store->close();
0493         image->addAnnotation(KisAnnotationSP(new KisAnnotation("exif", "", data)));
0494     }
0495 
0496 
0497     // layer styles
0498     location = external ? QString() : uri;
0499     location += m_d->imageName + LAYER_STYLES_PATH;
0500     if (store->hasFile(location)) {
0501 
0502         KisAslLayerStyleSerializer serializer;
0503         store->open(location);
0504         {
0505             KoStoreDevice device(store);
0506             device.open(QIODevice::ReadOnly);
0507 
0508             /**
0509              * ASL loading code cannot work with non-sequential IO devices,
0510              * so convert the device beforehand!
0511              */
0512             QByteArray buf = device.readAll();
0513             QBuffer raDevice(&buf);
0514             raDevice.open(QIODevice::ReadOnly);
0515             serializer.readFromDevice(raDevice);
0516         }
0517         store->close();
0518 
0519         if (serializer.isValid()) {
0520             const QString resourceLocation = m_d->document->embeddedResourcesStorageId();
0521             serializer.assignAllLayerStylesToLayers(image->root(), resourceLocation);
0522 
0523         } else {
0524             warnKrita << "WARNING: Couldn't load layer styles library from .kra!";
0525         }
0526     }
0527 
0528     if (m_d->document && m_d->document->documentInfo()->aboutInfo("title").isNull())
0529         m_d->document->documentInfo()->setAboutInfo("title", m_d->imageName);
0530     if (m_d->document && m_d->document->documentInfo()->aboutInfo("comment").isNull())
0531         m_d->document->documentInfo()->setAboutInfo("comment", m_d->imageComment);
0532 
0533     loadAssistants(store, uri, external);
0534 
0535     // Annotations
0536     Q_FOREACH(KisAnnotationSP annotation, m_d->annotations) {
0537         QByteArray ba;
0538         location = external ? QString() : uri;
0539         location += m_d->imageName + ANNOTATIONS_PATH + annotation->type();
0540         if (store->hasFile(location)) {
0541             store->open(location);
0542             KoStoreDevice device(store);
0543             device.open(QIODevice::ReadOnly);
0544             ba = device.readAll();
0545             device.close();
0546             store->close();
0547             annotation->setAnnotation(ba);
0548             m_d->document->image()->addAnnotation(annotation);
0549         }
0550     }
0551 
0552 }
0553 
0554 void KisKraLoader::loadResources(KoStore *store, KisDocument *doc)
0555 {
0556     QList<KoColorSetSP> list;
0557     Q_FOREACH (const QString &filename, m_d->paletteFilenames) {
0558         KoColorSetSP newPalette(new KoColorSet(filename));
0559         store->open(m_d->imageName + PALETTE_PATH + filename);
0560 
0561         QByteArray data = store->read(store->size());
0562         if (data.size() > 0) {
0563             newPalette->fromByteArray(data, KisGlobalResourcesInterface::instance());
0564             store->close();
0565             list.append(newPalette);
0566         } else {
0567             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));
0568         }
0569     }
0570     doc->setPaletteList(list);
0571 
0572     Q_FOREACH(const KoResourceSignature &resourceItem, m_d->resources) {
0573         KisResourceModel model(resourceItem.type);
0574         if (model.resourcesForMD5(resourceItem.md5sum).isEmpty()) {
0575             store->open(RESOURCE_PATH + '/' + resourceItem.type + '/' + resourceItem.filename);
0576 
0577             if (!store->isOpen()) {
0578                 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));
0579                 continue;
0580             }
0581 
0582             /// don't try to load the resource if its file is empty
0583             /// (which is a sign of a failed save operation)
0584             if (!store->device()->atEnd() && !doc->linkedResourcesStorageId().isEmpty()) {
0585                 bool result = model.importResource(resourceItem.filename, store->device(), false, doc->linkedResourcesStorageId());
0586                 if (!result) {
0587                     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));
0588                 }
0589             }
0590 
0591             store->close();
0592         }
0593     }
0594 }
0595 
0596 void KisKraLoader::loadStoryboards(KoStore *store, KisDocument */*doc*/)
0597 {
0598     if (!store->hasFile(m_d->imageName + STORYBOARD_PATH + "index.xml")) return;
0599 
0600     if (store->open(m_d->imageName + STORYBOARD_PATH + "index.xml")) {
0601         QByteArray data = store->read(store->size());
0602         QDomDocument document;
0603         document.setContent(data);
0604         store->close();
0605 
0606         QDomElement root = document.documentElement();
0607         QDomNode node;
0608         for (node = root.lastChild(); !node.isNull(); node = node.previousSibling()) {
0609             if (node.isElement()) {
0610                 QDomElement element = node.toElement();
0611                 if (element.tagName() == "StoryboardItemList") {
0612                     loadStoryboardItemList(element);
0613                 } else if (element.tagName() == "StoryboardCommentList") {
0614                     loadStoryboardCommentList(element);
0615                 }
0616             }
0617         }
0618     }
0619 }
0620 
0621 void KisKraLoader::loadAnimationMetadata(KoStore *store, KisImageSP image)
0622 {
0623     if (!store->hasFile(m_d->imageName + ANIMATION_METADATA_PATH + "index.xml")) return;
0624 
0625     if (store->open(m_d->imageName + ANIMATION_METADATA_PATH + "index.xml")) {
0626         QByteArray data = store->read(store->size());
0627         QDomDocument document;
0628         document.setContent(data);
0629         store->close();
0630 
0631         QDomElement root = document.documentElement();
0632         loadAnimationMetadataFromXML(root, image);
0633     }
0634 }
0635 
0636 void KisKraLoader::loadAudio(KoStore *store, KisDocument *kisDoc)
0637 {
0638     if (!store->hasFile(m_d->imageName + AUDIO_PATH + "index.xml")) return;
0639 
0640     if (store->open(m_d->imageName + AUDIO_PATH + "index.xml")) {
0641         QByteArray byteData = store->read(store->size());
0642         QDomDocument xmlDocument;
0643         xmlDocument.setContent(byteData);
0644         store->close();
0645 
0646         QDomElement root = xmlDocument.documentElement();
0647         loadAudioXML(xmlDocument, root, kisDoc);
0648     }
0649 }
0650 
0651 void KisKraLoader::backCompat_loadAudio(const QDomElement& elem, KisImageSP image, KisDocument *document)
0652 {
0653     QDomDocument dom;
0654     dom.appendChild(dom.importNode(elem, true));
0655     QDomElement qElement = dom.firstChildElement();
0656 
0657     QString fileName;
0658     if (KisDomUtils::loadValue(qElement, "masterChannelPath", &fileName)) {
0659         fileName = QDir::toNativeSeparators(fileName);
0660 
0661         QDir baseDirectory = QFileInfo(m_d->document->localFilePath()).absoluteDir();
0662         fileName = QDir::cleanPath( baseDirectory.filePath(fileName) );
0663 
0664         QFileInfo info(fileName);
0665 
0666         if (!info.exists()) {
0667             KisCursorOverrideHijacker cursorHijacker;
0668 
0669             QString msg = i18nc(
0670                         "@info",
0671                         "Audio channel file \"%1\" doesn't exist!\n\n"
0672                         "Expected path:\n"
0673                         "%2\n\n"
0674                         "Do you want to locate it manually?", info.fileName(), info.absoluteFilePath());
0675 
0676             int result = QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "File not found"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
0677 
0678             if (result == QMessageBox::Yes) {
0679                 info.setFile(KisImportExportManager::askForAudioFileName(info.absolutePath(), 0));
0680             }
0681         }
0682 
0683         if (info.exists()) {
0684             QVector<QFileInfo> clipFiles;
0685 
0686             clipFiles << info;
0687 
0688             document->setAudioTracks(clipFiles);
0689         }
0690     }
0691 
0692     // Note: Muting has been removed from backCompat due to it no longer being document-specific.
0693 
0694     qreal audioVolume = 1.0;
0695     if (KisDomUtils::loadValue(qElement, "audioVolume", &audioVolume)) {
0696         document->setAudioVolume(audioVolume);
0697     }
0698 }
0699 
0700 vKisNodeSP KisKraLoader::selectedNodes() const
0701 {
0702     return m_d->selectedNodes;
0703 }
0704 
0705 QList<KisPaintingAssistantSP> KisKraLoader::assistants() const
0706 {
0707     return m_d->assistants;
0708 }
0709 
0710 StoryboardItemList KisKraLoader::storyboardItemList() const
0711 {
0712     return m_d->storyboardItemList;
0713 }
0714 
0715 StoryboardCommentList KisKraLoader::storyboardCommentList() const
0716 {
0717     return m_d->storyboardCommentList;
0718 }
0719 QStringList KisKraLoader::errorMessages() const
0720 {
0721     return m_d->errorMessages;
0722 }
0723 
0724 QStringList KisKraLoader::warningMessages() const
0725 {
0726     return m_d->warningMessages;
0727 }
0728 
0729 QString KisKraLoader::imageName() const
0730 {
0731     return m_d->imageName;
0732 }
0733 
0734 
0735 void KisKraLoader::loadAssistants(KoStore *store, const QString &uri, bool external)
0736 {
0737     QString file_path;
0738     QString location;
0739     QMap<int ,KisPaintingAssistantHandleSP> handleMap;
0740     KisPaintingAssistant* assistant = 0;
0741     const QColor globalColor = m_d->document->assistantsGlobalColor();
0742 
0743     QMap<QString,QString>::const_iterator loadedAssistant = m_d->assistantsFilenames.constBegin();
0744     while (loadedAssistant != m_d->assistantsFilenames.constEnd()){
0745         const KisPaintingAssistantFactory* factory = KisPaintingAssistantFactoryRegistry::instance()->get(loadedAssistant.value());
0746         if (factory) {
0747             assistant = factory->createPaintingAssistant();
0748             location = external ? QString() : uri;
0749             location += m_d->imageName + ASSISTANTS_PATH;
0750             file_path = location + loadedAssistant.key();
0751             assistant->loadXml(store, handleMap, file_path);
0752             assistant->setAssistantGlobalColorCache(globalColor);
0753 
0754             //If an assistant has too few handles than it should according to it's own setup, just don't load it//
0755             if (assistant->handles().size()==assistant->numHandles()){
0756                 m_d->assistants.append(toQShared(assistant));
0757             }
0758         }
0759         loadedAssistant++;
0760     }
0761 }
0762 
0763 void KisKraLoader::loadAnimationMetadataFromXML(const QDomElement &element, KisImageSP image)
0764 {
0765     QDomDocument qDom;
0766     QDomNode node = element;
0767     qDom.appendChild(qDom.importNode(node, true));
0768     QDomElement rootElement = qDom.firstChildElement();
0769 
0770     float framerate;
0771     KisTimeSpan range;
0772     int currentTime;
0773     QString string;
0774 
0775     KisImageAnimationInterface *animation = image->animationInterface();
0776 
0777     if (KisDomUtils::loadValue(rootElement, "framerate", &framerate)) {
0778         animation->setFramerate(framerate);
0779     }
0780 
0781     if (KisDomUtils::loadValue(rootElement, "range", &range)) {
0782         animation->setDocumentRange(range);
0783     }
0784 
0785     if (KisDomUtils::loadValue(rootElement, "currentTime", &currentTime)) {
0786         animation->switchCurrentTimeAsync(currentTime);
0787     }
0788 
0789     {
0790         int initialFrameNumber = -1;
0791         QDomElement exportElement = rootElement.firstChildElement("export-settings");
0792         if (!exportElement.isNull()) {
0793             if (KisDomUtils::loadValue(exportElement, "sequenceFilePath", &string)) {
0794                 animation->setExportSequenceFilePath(string);
0795             }
0796 
0797             if (KisDomUtils::loadValue(exportElement, "sequenceBaseName", &string)) {
0798                 animation->setExportSequenceBaseName(string);
0799             }
0800 
0801             if (KisDomUtils::loadValue(exportElement, "sequenceInitialFrameNumber", &initialFrameNumber)) {
0802                 animation->setExportInitialFrameNumber(initialFrameNumber);
0803             }
0804         }
0805     }
0806 
0807     animation->setExportSequenceBaseName(string);
0808 }
0809 
0810 KisNodeSP KisKraLoader::loadNodes(const QDomElement& element, KisImageSP image, KisNodeSP parent)
0811 {
0812 
0813     QDomNode node = element.firstChild();
0814     QDomNode child;
0815 
0816     if (!node.isNull()) {
0817 
0818         if (node.isElement()) {
0819 
0820             // See https://bugs.kde.org/show_bug.cgi?id=408963, where there is a selection mask that is a child of the
0821             // the projection. That needs to be treated as a global selection, so we keep track of those.
0822             vKisNodeSP topLevelSelectionMasks;
0823             if (node.nodeName().toUpper() == LAYERS.toUpper() || node.nodeName().toUpper() == MASKS.toUpper()) {
0824                 for (child = node.lastChild(); !child.isNull(); child = child.previousSibling()) {
0825                     KisNodeSP node = loadNode(child.toElement(), image);
0826 
0827                     if (node && parent.data() == image->rootLayer().data() && node->inherits("KisSelectionMask") && image->rootLayer()->childCount() > 0) {
0828                         topLevelSelectionMasks << node;
0829                         continue;
0830                     }
0831 
0832                     if (node ) {
0833                         image->addNode(node, parent);
0834                         if (node->inherits("KisLayer") && child.childNodes().count() > 0) {
0835                             loadNodes(child.toElement(), image, node);
0836                         }
0837                     }
0838                 }
0839 
0840                 KisSelectionMaskSP activeSelectionMask;
0841                 Q_FOREACH (KisNodeSP node, topLevelSelectionMasks) {
0842                     KisSelectionMask *mask = qobject_cast<KisSelectionMask*>(node.data());
0843                     if (mask->active()) {
0844                         if (activeSelectionMask) {
0845                             m_d->warningMessages << i18n("Two global selection masks in active state found. \"%1\" is kept active, \"%2\" is deactivated", activeSelectionMask->name(), mask->name());
0846                             mask->setActive(false);
0847                             KIS_ASSERT(!mask->active());
0848                         } else {
0849                             activeSelectionMask = mask;
0850                         }
0851                     }
0852 
0853                     image->addNode(mask, parent);
0854                 }
0855             }
0856         }
0857     }
0858 
0859     return parent;
0860 }
0861 
0862 #include <KoColorSpaceBlendingPolicy.h>
0863 
0864 KisNodeSP KisKraLoader::loadNode(const QDomElement& element, KisImageSP image)
0865 {
0866     // Nota bene: If you add new properties to layers, you should
0867     // ALWAYS define a default value in case the property is not
0868     // present in the layer definition: this helps a LOT with backward
0869     // compatibility.
0870     QString name = element.attribute(NAME, "No Name");
0871 
0872     QUuid id = QUuid(element.attribute(UUID, QUuid().toString()));
0873 
0874     qint32 x = element.attribute(X, "0").toInt();
0875     qint32 y = element.attribute(Y, "0").toInt();
0876 
0877     qint32 opacity = element.attribute(OPACITY, QString::number(OPACITY_OPAQUE_U8)).toInt();
0878     if (opacity < OPACITY_TRANSPARENT_U8) opacity = OPACITY_TRANSPARENT_U8;
0879     if (opacity > OPACITY_OPAQUE_U8) opacity = OPACITY_OPAQUE_U8;
0880 
0881     const KoColorSpace* colorSpace = 0;
0882     if ((element.attribute(COLORSPACE_NAME)).isNull()) {
0883         dbgFile << "No attribute color space for layer: " << name;
0884         colorSpace = image->colorSpace();
0885     }
0886     else {
0887         QString colorspacename = element.attribute(COLORSPACE_NAME);
0888         QString profileProductName;
0889 
0890         convertColorSpaceNames(colorspacename, profileProductName);
0891 
0892         QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id();
0893         QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id();
0894         dbgFile << "Searching color space: " << colorspacename << colorspaceModel << colorspaceDepth << " for layer: " << name;
0895         // use default profile - it will be replaced later in completeLoading
0896 
0897         colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, "");
0898         dbgFile << "found colorspace" << colorSpace;
0899         if (!colorSpace) {
0900             m_d->warningMessages << i18n("Layer %1 specifies an unsupported color model: %2.", name, colorspacename);
0901             return 0;
0902         }
0903     }
0904 
0905     const bool visible = element.attribute(VISIBLE, "1") == "0" ? false : true;
0906     const bool locked = element.attribute(LOCKED, "0") == "0" ? false : true;
0907     const bool collapsed = element.attribute(COLLAPSED, "0") == "0" ? false : true;
0908     int colorLabelIndex = element.attribute(COLOR_LABEL, "0").toInt();
0909     QVector<QColor> labels = KisNodeViewColorScheme::instance()->allColorLabels();
0910     if (colorLabelIndex >= labels.size()) {
0911         colorLabelIndex = labels.size() - 1;
0912     }
0913 
0914     // Now find out the layer type and do specific handling
0915     QString nodeType;
0916 
0917     if (m_d->syntaxVersion == 1) {
0918         nodeType = element.attribute("layertype");
0919         if (nodeType.isEmpty()) {
0920             nodeType = PAINT_LAYER;
0921         }
0922     }
0923     else {
0924         nodeType = element.attribute(NODE_TYPE);
0925     }
0926 
0927     if (nodeType.isEmpty()) {
0928         m_d->warningMessages << i18n("Layer %1 has an unsupported type.", name);
0929         return 0;
0930     }
0931 
0932 
0933 
0934     KisNodeSP node = 0;
0935 
0936     if (nodeType == PAINT_LAYER)
0937         node = loadPaintLayer(element, image, name, colorSpace, opacity);
0938     else if (nodeType == GROUP_LAYER)
0939         node = loadGroupLayer(element, image, name, colorSpace, opacity);
0940     else if (nodeType == ADJUSTMENT_LAYER)
0941         node = loadAdjustmentLayer(element, image, name, colorSpace, opacity);
0942     else if (nodeType == SHAPE_LAYER)
0943         node = loadShapeLayer(element, image, name, colorSpace, opacity);
0944     else if (nodeType == GENERATOR_LAYER)
0945         node = loadGeneratorLayer(element, image, name, colorSpace, opacity);
0946     else if (nodeType == CLONE_LAYER)
0947         node = loadCloneLayer(element, image, name, colorSpace, opacity);
0948     else if (nodeType == FILTER_MASK)
0949         node = loadFilterMask(image, element);
0950     else if (nodeType == TRANSFORM_MASK)
0951         node = loadTransformMask(image, element);
0952     else if (nodeType == TRANSPARENCY_MASK)
0953         node = loadTransparencyMask(image, element);
0954     else if (nodeType == SELECTION_MASK)
0955         node = loadSelectionMask(image, element);
0956     else if (nodeType == COLORIZE_MASK)
0957         node = loadColorizeMask(image, element, colorSpace);
0958     else if (nodeType == FILE_LAYER)
0959         node = loadFileLayer(element, image, name, opacity, colorSpace);
0960     else if (nodeType == REFERENCE_IMAGES_LAYER)
0961         node = loadReferenceImagesLayer(element, image);
0962     else {
0963         m_d->warningMessages << i18n("Layer %1 has an unsupported type: %2.", name, nodeType);
0964         return 0;
0965     }
0966 
0967     // Loading the node went wrong. Return empty node and leave to
0968     // upstream to complain to the user
0969     if (!node) {
0970         m_d->warningMessages << i18n("Failure loading layer %1 of type: %2.", name, nodeType);
0971         return 0;
0972     }
0973 
0974     node->setVisible(visible, true);
0975     node->setUserLocked(locked);
0976     node->setCollapsed(collapsed);
0977     node->setColorLabelIndex(colorLabelIndex);
0978     node->setX(x);
0979     node->setY(y);
0980     node->setName(name);
0981 
0982     if (! id.isNull())          // if no uuid in file, new one has been generated already
0983         node->setUuid(id);
0984 
0985     if (node->inherits("KisLayer") || node->inherits("KisColorizeMask")) {
0986         QString compositeOpName = element.attribute(COMPOSITE_OP, "normal");
0987         node->setCompositeOpId(compositeOpName);
0988 
0989         if (m_d->kritaVersion < QVersionNumber(5, 2) &&
0990             colorSpace->colorModelId() == CMYKAColorModelID &&
0991             subtractiveBlendingModesInCmyk().contains(compositeOpName)) {
0992 
0993             m_d->warningMessages <<
0994                 i18n("Layer \"%1\" has blending mode \"%2\" that has changed its "
0995                     "behavior for CMYK color in Krita 5.2. Please check the "
0996                     "result and consider enabling legacy \"Additive\" algorithm in "
0997                     "Settings->Configure Krita->General->Tools->CMYK blending mode",
0998                     name, KoCompositeOpRegistry::instance().getKoID(compositeOpName).name());
0999         }
1000     }
1001 
1002     if (node->inherits("KisLayer")) {
1003         KisLayer* layer           = qobject_cast<KisLayer*>(node.data());
1004         QBitArray channelFlags    = stringToFlags(element.attribute(CHANNEL_FLAGS, ""), colorSpace->channelCount());
1005         layer->setChannelFlags(channelFlags);
1006 
1007         if (element.hasAttribute(LAYER_STYLE_UUID)) {
1008             QString uuidString = element.attribute(LAYER_STYLE_UUID);
1009             QUuid uuid(uuidString);
1010             if (!uuid.isNull()) {
1011                 KisPSDLayerStyleSP dumbLayerStyle(new KisPSDLayerStyle());
1012                 dumbLayerStyle->setUuid(uuid);
1013                 layer->setLayerStyle(dumbLayerStyle->cloneWithResourcesSnapshot(KisGlobalResourcesInterface::instance(), 0));
1014             } else {
1015                 warnKrita << "WARNING: Layer style for layer" << layer->name() << "contains invalid UUID" << uuidString;
1016             }
1017         }
1018     }
1019 
1020     if (node->inherits("KisGroupLayer")) {
1021         if (element.hasAttribute(PASS_THROUGH_MODE)) {
1022             bool value = element.attribute(PASS_THROUGH_MODE, "0") != "0";
1023 
1024             KisGroupLayer *group = qobject_cast<KisGroupLayer*>(node.data());
1025             group->setPassThroughMode(value);
1026         }
1027     }
1028 
1029     const bool timelineEnabled = element.attribute(VISIBLE_IN_TIMELINE, "0") == "0" ? false : true;
1030     node->setPinnedToTimeline(timelineEnabled);
1031 
1032     if (node->inherits("KisPaintLayer")) {
1033         KisPaintLayer* layer = qobject_cast<KisPaintLayer*>(node.data());
1034         QBitArray channelLockFlags = stringToFlags(element.attribute(CHANNEL_LOCK_FLAGS, ""), colorSpace->channelCount());
1035         layer->setChannelLockFlags(channelLockFlags);
1036 
1037         bool onionEnabled = element.attribute(ONION_SKIN_ENABLED, "0") == "0" ? false : true;
1038         layer->setOnionSkinEnabled(onionEnabled);
1039     }
1040 
1041     if (element.attribute(FILE_NAME).isNull()) {
1042         m_d->layerFilenames[node.data()] = name;
1043     }
1044     else {
1045         m_d->layerFilenames[node.data()] = element.attribute(FILE_NAME);
1046     }
1047 
1048     if (element.hasAttribute("selected") && element.attribute("selected") == "true")  {
1049         m_d->selectedNodes.append(node);
1050     }
1051 
1052     if (element.hasAttribute(KEYFRAME_FILE)) {
1053         m_d->keyframeFilenames.insert(node.data(), element.attribute(KEYFRAME_FILE));
1054     }
1055 
1056     return node;
1057 }
1058 
1059 
1060 KisNodeSP KisKraLoader::loadPaintLayer(const QDomElement& element, KisImageSP image,
1061                                        const QString& name, const KoColorSpace* cs, quint32 opacity)
1062 {
1063     Q_UNUSED(element);
1064     KisPaintLayer* layer;
1065 
1066     layer = new KisPaintLayer(image, name, opacity, cs);
1067     Q_CHECK_PTR(layer);
1068     return layer;
1069 
1070 }
1071 
1072 KisNodeSP KisKraLoader::loadFileLayer(const QDomElement& element, KisImageSP image, const QString& name, quint32 opacity, const KoColorSpace *fallbackColorSpace)
1073 {
1074     QString filename = element.attribute("source", QString());
1075     if (filename.isNull()) return 0;
1076     bool scale = (element.attribute("scale", "true")  == "true");
1077     int scalingMethod = element.attribute("scalingmethod", "-1").toInt();
1078     if (scalingMethod < 0) {
1079         if (scale) {
1080             scalingMethod = KisFileLayer::ToImagePPI;
1081         }
1082         else {
1083             scalingMethod = KisFileLayer::None;
1084         }
1085     }
1086     QString scalingFilter = element.attribute("scalingfilter", "Bicubic");
1087 
1088     QString documentPath;
1089     if (m_d->document) {
1090         documentPath = m_d->document->path();
1091     }
1092     QFileInfo info(documentPath);
1093     QString basePath = info.absolutePath();
1094 
1095 #ifndef Q_OS_ANDROID
1096     QString fullPath = QDir(basePath).filePath(QDir::cleanPath(filename));
1097 #else
1098     QString fullPath = filename;
1099 #endif
1100     if (!QFileInfo(fullPath).exists()) {
1101         KisCursorOverrideHijacker cursorHijacker;
1102 
1103         QString msg = i18nc(
1104                     "@info",
1105                     "The file associated to a file layer with the name \"%1\" is not found.\n\n"
1106                     "Expected path:\n"
1107                     "%2\n\n"
1108                     "Do you want to locate it manually?", name, fullPath);
1109 
1110         int result = QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "File not found"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
1111 
1112         if (result == QMessageBox::Yes) {
1113 
1114             KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument");
1115             dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import));
1116             dialog.setDefaultDir(basePath);
1117             QString url = dialog.filename();
1118 
1119             if (!QFileInfo(basePath).exists()) {
1120                 filename = url;
1121             } else {
1122                 QDir d(basePath);
1123                 filename = d.relativeFilePath(url);
1124             }
1125         }
1126     }
1127 
1128     KisLayer *layer = new KisFileLayer(image, basePath, filename, (KisFileLayer::ScalingMethod)scalingMethod, scalingFilter, name, opacity, fallbackColorSpace);
1129     Q_CHECK_PTR(layer);
1130 
1131     return layer;
1132 }
1133 
1134 KisNodeSP KisKraLoader::loadGroupLayer(const QDomElement& element, KisImageSP image,
1135                                        const QString& name, const KoColorSpace* cs, quint32 opacity)
1136 {
1137     Q_UNUSED(element);
1138     Q_UNUSED(cs);
1139     QString attr;
1140     KisGroupLayer* layer;
1141 
1142     layer = new KisGroupLayer(image, name, opacity);
1143     Q_CHECK_PTR(layer);
1144 
1145     return layer;
1146 
1147 }
1148 
1149 KisNodeSP KisKraLoader::loadAdjustmentLayer(const QDomElement& element, KisImageSP image,
1150                                             const QString& name, const KoColorSpace* cs, quint32 opacity)
1151 {
1152     // XXX: do something with filterversion?
1153     Q_UNUSED(cs);
1154     QString attr;
1155     KisAdjustmentLayer* layer;
1156     QString filtername;
1157     QString legacy = filtername;
1158 
1159     if ((filtername = element.attribute(FILTER_NAME)).isNull()) {
1160         // XXX: Invalid adjustment layer! We should warn about it!
1161         warnFile << "No filter in adjustment layer";
1162         return 0;
1163     }
1164 
1165     //get deprecated filters.
1166     if (filtername=="brightnesscontrast") {
1167         legacy = filtername;
1168         filtername = "perchannel";
1169     }
1170     if (filtername=="left edge detections"
1171             || filtername=="right edge detections"
1172             || filtername=="top edge detections"
1173             || filtername=="bottom edge detections") {
1174         legacy = filtername;
1175         filtername = "edge detection";
1176     }
1177 
1178     KisFilterSP f = KisFilterRegistry::instance()->value(filtername);
1179     if (!f) {
1180         warnFile << "No filter for filtername" << filtername << "";
1181         return 0; // XXX: We don't have this filter. We should warn about it!
1182     }
1183 
1184     KisFilterConfigurationSP  kfc = f->defaultConfiguration(KisGlobalResourcesInterface::instance());
1185     kfc->createLocalResourcesSnapshot();
1186     kfc->setProperty("legacy", legacy);
1187     if (legacy=="brightnesscontrast") {
1188         kfc->setProperty("colorModel", cs->colorModelId().id());
1189     }
1190 
1191     // We'll load the configuration and the selection later.
1192     layer = new KisAdjustmentLayer(image, name, kfc, 0);
1193     Q_CHECK_PTR(layer);
1194 
1195     layer->setOpacity(opacity);
1196 
1197     return layer;
1198 
1199 }
1200 
1201 
1202 KisNodeSP KisKraLoader::loadShapeLayer(const QDomElement& element, KisImageSP image,
1203                                        const QString& name, const KoColorSpace* cs, quint32 opacity)
1204 {
1205 
1206     Q_UNUSED(element);
1207     Q_UNUSED(cs);
1208 
1209     QString attr;
1210     KoShapeControllerBase * shapeController = 0;
1211     if (m_d->document) {
1212         shapeController = m_d->document->shapeController();
1213     }
1214     KisShapeLayer* layer = new KisShapeLayer(shapeController, image, name, opacity);
1215     Q_CHECK_PTR(layer);
1216 
1217     return layer;
1218 
1219 }
1220 
1221 
1222 KisNodeSP KisKraLoader::loadGeneratorLayer(const QDomElement& element, KisImageSP image,
1223                                            const QString& name, const KoColorSpace* cs, quint32 opacity)
1224 {
1225     Q_UNUSED(cs);
1226     // XXX: do something with generator version?
1227     KisGeneratorLayer* layer;
1228     QString generatorname = element.attribute(GENERATOR_NAME);
1229 
1230     if (generatorname.isNull()) {
1231         // XXX: Invalid generator layer! We should warn about it!
1232         warnFile << "No generator in generator layer";
1233         return 0;
1234     }
1235 
1236     KisGeneratorSP generator = KisGeneratorRegistry::instance()->value(generatorname);
1237     if (!generator) {
1238         warnFile << "No generator for generatorname" << generatorname << "";
1239         return 0; // XXX: We don't have this generator. We should warn about it!
1240     }
1241 
1242     KisFilterConfigurationSP  kgc = generator->defaultConfiguration(KisGlobalResourcesInterface::instance());
1243     kgc->createLocalResourcesSnapshot();
1244 
1245     // We'll load the configuration and the selection later.
1246     layer = new KisGeneratorLayer(image, name, kgc, 0);
1247     Q_CHECK_PTR(layer);
1248 
1249     layer->setOpacity(opacity);
1250 
1251     return layer;
1252 
1253 }
1254 
1255 KisNodeSP KisKraLoader::loadCloneLayer(const QDomElement& element, KisImageSP image,
1256                                        const QString& name, const KoColorSpace* cs, quint32 opacity)
1257 {
1258     Q_UNUSED(cs);
1259 
1260     KisCloneLayerSP layer = new KisCloneLayer(0, image, name, opacity);
1261 
1262     KisNodeUuidInfo info;
1263     if (! (element.attribute(CLONE_FROM_UUID)).isNull()) {
1264         info = KisNodeUuidInfo(QUuid(element.attribute(CLONE_FROM_UUID)));
1265     } else {
1266         if ((element.attribute(CLONE_FROM)).isNull()) {
1267             return 0;
1268         } else {
1269             info = KisNodeUuidInfo(element.attribute(CLONE_FROM));
1270         }
1271     }
1272     layer->setCopyFromInfo(info);
1273 
1274     if ((element.attribute(CLONE_TYPE)).isNull()) {
1275         return 0;
1276     } else {
1277         layer->setCopyType((CopyLayerType) element.attribute(CLONE_TYPE).toInt());
1278     }
1279 
1280     return layer;
1281 }
1282 
1283 
1284 KisNodeSP KisKraLoader::loadFilterMask(KisImageSP image, const QDomElement& element)
1285 {
1286     QString attr;
1287     KisFilterMask* mask;
1288     QString filtername;
1289 
1290     // XXX: should we check the version?
1291 
1292     if ((filtername = element.attribute(FILTER_NAME)).isNull()) {
1293         // XXX: Invalid filter layer! We should warn about it!
1294         warnFile << "No filter in filter layer";
1295         return 0;
1296     }
1297 
1298     KisFilterSP f = KisFilterRegistry::instance()->value(filtername);
1299     if (!f) {
1300         warnFile << "No filter for filtername" << filtername << "";
1301         return 0; // XXX: We don't have this filter. We should warn about it!
1302     }
1303 
1304     KisFilterConfigurationSP  kfc = f->defaultConfiguration(KisGlobalResourcesInterface::instance());
1305     kfc->createLocalResourcesSnapshot();
1306 
1307     // We'll load the configuration and the selection later.
1308     mask = new KisFilterMask(image);
1309     mask->setFilter(kfc);
1310     Q_CHECK_PTR(mask);
1311 
1312     return mask;
1313 }
1314 
1315 KisNodeSP KisKraLoader::loadTransformMask(KisImageSP image, const QDomElement& element)
1316 {
1317     Q_UNUSED(element);
1318 
1319     KisTransformMask* mask;
1320 
1321     /**
1322      * We'll load the transform configuration later on a stage
1323      * of binary data loading
1324      */
1325     mask = new KisTransformMask(image, "");
1326     Q_CHECK_PTR(mask);
1327 
1328     return mask;
1329 }
1330 
1331 KisNodeSP KisKraLoader::loadTransparencyMask(KisImageSP image, const QDomElement& element)
1332 {
1333     Q_UNUSED(element);
1334     KisTransparencyMask* mask = new KisTransparencyMask(image, "");
1335     Q_CHECK_PTR(mask);
1336 
1337     return mask;
1338 }
1339 
1340 KisNodeSP KisKraLoader::loadSelectionMask(KisImageSP image, const QDomElement& element)
1341 {
1342     KisSelectionMaskSP mask = new KisSelectionMask(image);
1343     bool active = element.attribute(ACTIVE, "1") == "0" ? false : true;
1344     mask->setActive(active);
1345     Q_CHECK_PTR(mask);
1346 
1347     return mask;
1348 }
1349 
1350 KisNodeSP KisKraLoader::loadColorizeMask(KisImageSP image, const QDomElement& element, const KoColorSpace *colorSpace)
1351 {
1352     KisColorizeMaskSP mask = new KisColorizeMask(image, "");
1353     const bool editKeystrokes = element.attribute(COLORIZE_EDIT_KEYSTROKES, "1") == "0" ? false : true;
1354     const bool showColoring = element.attribute(COLORIZE_SHOW_COLORING, "1") == "0" ? false : true;
1355 
1356     KisBaseNode::PropertyList props = mask->sectionModelProperties();
1357     KisLayerPropertiesIcons::setNodeProperty(&props, KisLayerPropertiesIcons::colorizeEditKeyStrokes, editKeystrokes);
1358     KisLayerPropertiesIcons::setNodeProperty(&props, KisLayerPropertiesIcons::colorizeShowColoring, showColoring);
1359     mask->setSectionModelProperties(props);
1360 
1361     const bool useEdgeDetection = KisDomUtils::toInt(element.attribute(COLORIZE_USE_EDGE_DETECTION, "0"));
1362     const qreal edgeDetectionSize = KisDomUtils::toDouble(element.attribute(COLORIZE_EDGE_DETECTION_SIZE, "4"));
1363     const qreal radius = KisDomUtils::toDouble(element.attribute(COLORIZE_FUZZY_RADIUS, "0"));
1364     const int cleanUp = KisDomUtils::toInt(element.attribute(COLORIZE_CLEANUP, "0"));
1365     const bool limitToDevice = KisDomUtils::toInt(element.attribute(COLORIZE_LIMIT_TO_DEVICE, "0"));
1366 
1367     mask->setUseEdgeDetection(useEdgeDetection);
1368     mask->setEdgeDetectionSize(edgeDetectionSize);
1369     mask->setFuzzyRadius(radius);
1370     mask->setCleanUpAmount(qreal(cleanUp) / 100.0);
1371     mask->setLimitToDeviceBounds(limitToDevice);
1372 
1373     delete mask->setColorSpace(colorSpace);
1374 
1375     return mask;
1376 }
1377 
1378 void KisKraLoader::loadCompositions(const QDomElement& elem, KisImageSP image)
1379 {
1380     QDomNode child;
1381 
1382     for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) {
1383 
1384         QDomElement e = child.toElement();
1385         QString name = e.attribute("name");
1386         bool exportEnabled = e.attribute("exportEnabled", "1") == "0" ? false : true;
1387 
1388         KisLayerCompositionSP composition(new KisLayerComposition(image, name));
1389         composition->setExportEnabled(exportEnabled);
1390 
1391         QDomNode value;
1392         for (value = child.lastChild(); !value.isNull(); value = value.previousSibling()) {
1393             QDomElement e = value.toElement();
1394             QUuid uuid(e.attribute("uuid"));
1395             bool visible = e.attribute("visible", "1") == "0" ? false : true;
1396             composition->setVisible(uuid, visible);
1397             bool collapsed = e.attribute("collapsed", "1") == "0" ? false : true;
1398             composition->setCollapsed(uuid, collapsed);
1399         }
1400 
1401         image->addComposition(composition);
1402     }
1403 }
1404 
1405 void KisKraLoader::loadAssistantsList(const QDomElement &elem)
1406 {
1407     QDomNode child;
1408     int count = 0;
1409     for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) {
1410         QDomElement e = child.toElement();
1411         QString type = e.attribute("type");
1412         QString file_name = e.attribute("filename");
1413         m_d->assistantsFilenames.insert(file_name,type);
1414         count++;
1415 
1416     }
1417 }
1418 
1419 void KisKraLoader::loadGrid(const QDomElement& elem)
1420 {
1421     QDomDocument dom;
1422     dom.appendChild(dom.importNode(elem, true));
1423     QDomElement domElement = dom.firstChildElement();
1424 
1425     KisGridConfig config;
1426     config.loadStaticData();
1427     config.loadDynamicDataFromXml(domElement);
1428     m_d->document->setGridConfig(config);
1429 }
1430 
1431 void KisKraLoader::loadGuides(const QDomElement& elem)
1432 {
1433     QDomDocument dom;
1434     dom.appendChild(dom.importNode(elem, true));
1435     QDomElement domElement = dom.firstChildElement();
1436 
1437     KisGuidesConfig guides;
1438     guides.loadFromXml(domElement);
1439     m_d->document->setGuidesConfig(guides);
1440 }
1441 
1442 void KisKraLoader::loadMirrorAxis(const QDomElement &elem)
1443 {
1444     QDomDocument dom;
1445     dom.appendChild(dom.importNode(elem, true));
1446     QDomElement domElement = dom.firstChildElement();
1447 
1448     KisMirrorAxisConfig mirrorAxis;
1449     mirrorAxis.loadFromXml(domElement);
1450     m_d->document->setMirrorAxisConfig(mirrorAxis);
1451 }
1452 
1453 void KisKraLoader::loadStoryboardItemList(const QDomElement& elem)
1454 {
1455     QDomNode child;
1456     int count = 0;
1457     for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) {
1458         QDomElement e = child.toElement();
1459         if (e.tagName() == "storyboarditem") {
1460             StoryboardItemSP item = toQShared( new StoryboardItem() );
1461             item->loadXML(e);
1462             count++;
1463             m_d->storyboardItemList.append(item);
1464         }
1465     }
1466 }
1467 
1468 void KisKraLoader::loadStoryboardCommentList(const QDomElement& elem)
1469 {
1470     QDomNode child;
1471     int count = 0;
1472     for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) {
1473         QDomElement e = child.toElement();
1474         if (e.tagName() == "storyboardcomment") {
1475             StoryboardComment comment;
1476             if (e.hasAttribute("visibility")) {
1477                 comment.visibility = e.attribute("visibility").toInt();
1478             }
1479             if (e.hasAttribute("name")) {
1480                 comment.name = e.attribute("name");
1481             }
1482             count++;
1483             m_d->storyboardCommentList.append(comment);
1484         }
1485     }
1486 }
1487 
1488 void KisKraLoader::loadAudioXML(QDomDocument &xmlDoc, QDomElement &xmlElement, KisDocument *kisDoc)
1489 {
1490     Q_UNUSED(xmlDoc);
1491     QDomNode audioClip = xmlElement.firstChild();
1492     if (audioClip.nodeName() == "audioClips") {
1493         QDomElement audioClipElement = audioClip.toElement();
1494         QVector<QFileInfo> clipFiles;
1495         qreal volume = 1.0;
1496         QDomNode clip;
1497         for (clip = audioClipElement.firstChild(); !clip.isNull(); clip = clip.nextSibling()) {
1498             QDomElement clipElem = clip.toElement();
1499 
1500             if (clipElem.hasAttribute("filePath")) {
1501                 QFileInfo f(clipElem.attribute("filePath"));
1502                 if (f.exists()) {
1503                     clipFiles << f;
1504                 }
1505             }
1506 
1507             if (clipElem.hasAttribute("volume")) {
1508                 volume = clipElem.attribute("volume").toDouble();
1509             }
1510         }
1511 
1512         kisDoc->setAudioTracks(clipFiles);
1513         kisDoc->setAudioVolume(volume);
1514     }
1515 }
1516 
1517 KisNodeSP KisKraLoader::loadReferenceImagesLayer(const QDomElement &elem, KisImageSP image)
1518 {
1519     KisSharedPtr<KisReferenceImagesLayer> layer =
1520             new KisReferenceImagesLayer(m_d->document->shapeController(), image);
1521 
1522     m_d->document->setReferenceImagesLayer(layer, false);
1523 
1524     for (QDomElement child = elem.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) {
1525         if (child.nodeName().toLower() == "referenceimage") {
1526             auto* reference = KisReferenceImage::fromXml(child);
1527             reference->setZIndex(layer->shapes().size());
1528             layer->addShape(reference);
1529         }
1530     }
1531 
1532     return layer;
1533 }