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", ¤tTime)) { 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 }