File indexing completed on 2024-05-26 04:33:32

0001 /*
0002  *  SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
0003  *  SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
0004  *  SPDX-FileCopyrightText: 2007-2008 Boudewijn Rempt <boud@valdyas.org>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "kis_kra_save_visitor.h"
0010 #include "kis_kra_tags.h"
0011 
0012 #include <QBuffer>
0013 #include <QByteArray>
0014 
0015 #include <KoColorProfile.h>
0016 #include <KoStore.h>
0017 #include <KoColorSpace.h>
0018 
0019 #include "lazybrush/kis_colorize_mask.h"
0020 #include <KisReferenceImage.h>
0021 #include <KisReferenceImagesLayer.h>
0022 #include <filter/kis_filter_configuration.h>
0023 #include <generator/kis_generator_layer.h>
0024 #include <kis_adjustment_layer.h>
0025 #include <kis_annotation.h>
0026 #include <kis_clone_layer.h>
0027 #include <kis_file_layer.h>
0028 #include <kis_filter_mask.h>
0029 #include <kis_group_layer.h>
0030 #include <kis_image.h>
0031 #include <kis_layer.h>
0032 #include <kis_mask.h>
0033 #include <kis_meta_data_backend_registry.h>
0034 #include <kis_meta_data_store.h>
0035 #include <kis_paint_layer.h>
0036 #include <kis_pixel_selection.h>
0037 #include <kis_selection.h>
0038 #include <kis_selection_component.h>
0039 #include <kis_selection_mask.h>
0040 #include <kis_shape_layer.h>
0041 #include <kis_transform_mask.h>
0042 #include <kis_transform_mask_params_interface.h>
0043 #include <kis_transparency_mask.h>
0044 
0045 #include "kis_config.h"
0046 #include "kis_store_paintdevice_writer.h"
0047 #include "flake/kis_shape_selection.h"
0048 
0049 #include "kis_raster_keyframe_channel.h"
0050 #include "kis_paint_device_frames_interface.h"
0051 
0052 #include "lazybrush/kis_lazy_fill_tools.h"
0053 #include <KoStoreDevice.h>
0054 #include "kis_colorize_dom_utils.h"
0055 #include "kis_dom_utils.h"
0056 
0057 
0058 using namespace KRA;
0059 
0060 KisKraSaveVisitor::KisKraSaveVisitor(KoStore *store, const QString & name, QMap<const KisNode*, QString> nodeFileNames)
0061     : KisNodeVisitor()
0062     , m_store(store)
0063     , m_external(false)
0064     , m_name(name)
0065     , m_nodeFileNames(nodeFileNames)
0066     , m_writer(new KisStorePaintDeviceWriter(store))
0067 {
0068 }
0069 
0070 KisKraSaveVisitor::~KisKraSaveVisitor()
0071 {
0072     delete m_writer;
0073 }
0074 
0075 void KisKraSaveVisitor::setExternalUri(const QString &uri)
0076 {
0077     m_external = true;
0078     m_uri = uri;
0079 }
0080 
0081 bool KisKraSaveVisitor::visit(KisExternalLayer * layer)
0082 {
0083     bool result = false;
0084     if (auto* referencesLayer = dynamic_cast<KisReferenceImagesLayer*>(layer)) {
0085         result = true;
0086         QList <KoShape *> shapes = referencesLayer->shapes();
0087         std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
0088         Q_FOREACH(KoShape *shape, shapes) {
0089             auto *reference = dynamic_cast<KisReferenceImage*>(shape);
0090             KIS_ASSERT_RECOVER_RETURN_VALUE(reference, false);
0091             bool saved = reference->saveImage(m_store);
0092             if (!saved) {
0093                 m_errorMessages << i18n("Failed to save reference image %1.", reference->internalFile());
0094                 result = false;
0095             }
0096         }
0097     }
0098     else if (KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(layer)) {
0099         if (!saveMetaData(layer)) {
0100             m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
0101             return false;
0102         }
0103         m_store->pushDirectory();
0104         QString location = getLocation(layer, DOT_SHAPE_LAYER);
0105         result = m_store->enterDirectory(location);
0106         if (!result) {
0107             m_errorMessages << i18n("Failed to open %1.", location);
0108         }
0109         else {
0110             result = shapeLayer->saveLayer(m_store);
0111             m_store->popDirectory();
0112         }
0113     }
0114     else if (KisFileLayer *fileLayer = dynamic_cast<KisFileLayer*>(layer)) {
0115         Q_UNUSED(fileLayer); // We don't save data for file layers, but we still want to save the masks.
0116         result = true;
0117     }
0118     return result && visitAllInverse(layer);
0119 }
0120 
0121 bool KisKraSaveVisitor::visit(KisPaintLayer *layer)
0122 {
0123     if (!savePaintDevice(layer->paintDevice(), getLocation(layer))) {
0124         m_errorMessages << i18n("Failed to save the pixel data for layer %1.", layer->name());
0125         return false;
0126     }
0127     if (!saveAnnotations(layer)) {
0128         m_errorMessages << i18n("Failed to save the annotations for layer %1.", layer->name());
0129         return false;
0130     }
0131     if (!saveMetaData(layer)) {
0132         m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
0133         return false;
0134     }
0135     return visitAllInverse(layer);
0136 }
0137 
0138 bool KisKraSaveVisitor::visit(KisGroupLayer *layer)
0139 {
0140     if (!saveMetaData(layer)) {
0141         m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
0142         return false;
0143     }
0144     return visitAllInverse(layer);
0145 }
0146 
0147 bool KisKraSaveVisitor::visit(KisAdjustmentLayer* layer)
0148 {
0149     if (!layer->filter()) {
0150         m_errorMessages << i18n("Failed to save the filter layer %1: it has no filter.", layer->name());
0151         return false;
0152     }
0153     if (!saveSelection(layer)) {
0154         m_errorMessages << i18n("Failed to save the selection for filter layer %1.", layer->name());
0155         return false;
0156     }
0157     if (!saveFilterConfiguration(layer)) {
0158         m_errorMessages << i18n("Failed to save the filter configuration for filter layer %1.", layer->name());
0159         return false;
0160     }
0161     if (!saveMetaData(layer)) {
0162         m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
0163         return false;
0164     }
0165     return visitAllInverse(layer);
0166 }
0167 
0168 bool KisKraSaveVisitor::visit(KisGeneratorLayer * layer)
0169 {
0170     if (!saveSelection(layer)) {
0171         m_errorMessages << i18n("Failed to save the selection for layer %1.", layer->name());
0172         return false;
0173     }
0174     if (!saveFilterConfiguration(layer)) {
0175         m_errorMessages << i18n("Failed to save the generator configuration for layer %1.", layer->name());
0176         return false;
0177     }
0178     if (!saveMetaData(layer)) {
0179         m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
0180         return false;
0181     }
0182     return visitAllInverse(layer);
0183 }
0184 
0185 bool KisKraSaveVisitor::visit(KisCloneLayer *layer)
0186 {
0187     // Clone layers do not have a profile
0188     if (!saveMetaData(layer)) {
0189         m_errorMessages << i18n("Failed to save the metadata for layer %1.", layer->name());
0190         return false;
0191     }
0192     return visitAllInverse(layer);
0193 }
0194 
0195 bool KisKraSaveVisitor::visit(KisFilterMask *mask)
0196 {
0197     if (!mask->filter()) {
0198         m_errorMessages << i18n("Failed to save filter mask %1. It has no filter.", mask->name());
0199         return false;
0200     }
0201     if (!saveSelection(mask)) {
0202         m_errorMessages << i18n("Failed to save the selection for filter mask %1.", mask->name());
0203         return false;
0204     }
0205     if (!saveFilterConfiguration(mask)) {
0206         m_errorMessages << i18n("Failed to save the filter configuration for filter mask %1.", mask->name());
0207         return false;
0208     }
0209     return true;
0210 }
0211 
0212 bool KisKraSaveVisitor::visit(KisTransformMask *mask)
0213 {
0214     QDomDocument doc("transform_params");
0215 
0216     QDomElement root = doc.createElement("transform_params");
0217 
0218     QDomElement main = doc.createElement("main");
0219     main.setAttribute("id", mask->transformParams()->id());
0220 
0221     QDomElement data = doc.createElement("data");
0222     mask->transformParams()->toXML(&data);
0223 
0224     doc.appendChild(root);
0225     root.appendChild(main);
0226     root.appendChild(data);
0227 
0228     QString location = getLocation(mask, DOT_TRANSFORMCONFIG);
0229     if (m_store->open(location)) {
0230         QByteArray a = doc.toByteArray();
0231         bool retval = m_store->write(a) == a.size();
0232 
0233         if (!retval) {
0234             warnFile << "Could not write transform mask configuration";
0235         }
0236         if (!m_store->close()) {
0237             warnFile << "Could not close store after writing transform mask configuration";
0238             retval = false;
0239         }
0240         return retval;
0241     }
0242     return false;
0243 }
0244 
0245 bool KisKraSaveVisitor::visit(KisTransparencyMask *mask)
0246 {
0247     if (!saveSelection(mask)) {
0248         m_errorMessages << i18n("Failed to save the selection for transparency mask %1.", mask->name());
0249         return false;
0250     }
0251     return true;
0252 }
0253 
0254 bool KisKraSaveVisitor::visit(KisSelectionMask *mask)
0255 {
0256     if (!saveSelection(mask)) {
0257         m_errorMessages << i18n("Failed to save the selection for local selection %1.", mask->name());
0258         return false;
0259     }
0260     return true;
0261 }
0262 
0263 bool KisKraSaveVisitor::visit(KisColorizeMask *mask)
0264 {
0265     m_store->pushDirectory();
0266     QString location = getLocation(mask, DOT_COLORIZE_MASK);
0267     bool result = m_store->enterDirectory(location);
0268 
0269     if (!result) {
0270         m_errorMessages << i18n("Failed to open %1.", location);
0271         return false;
0272     }
0273 
0274     if (!m_store->open("content.xml"))
0275         return false;
0276 
0277     KoStoreDevice storeDev(m_store);
0278 
0279     QDomDocument doc("doc");
0280     QDomElement root = doc.createElement("colorize");
0281     doc.appendChild(root);
0282     KisDomUtils::saveValue(&root, COLORIZE_KEYSTROKES_SECTION, QVector<KisLazyFillTools::KeyStroke>::fromList(mask->fetchKeyStrokesDirect()));
0283 
0284     QTextStream stream(&storeDev);
0285     stream.setCodec("UTF-8");
0286     stream << doc;
0287 
0288     if (!m_store->close())
0289         return false;
0290 
0291     int i = 0;
0292     Q_FOREACH (const KisLazyFillTools::KeyStroke &stroke, mask->fetchKeyStrokesDirect()) {
0293         const QString fileName = QString("%1_%2").arg(COLORIZE_KEYSTROKE).arg(i++);
0294         savePaintDevice(stroke.dev, fileName);
0295     }
0296 
0297     savePaintDevice(mask->coloringProjection(), COLORIZE_COLORING_DEVICE);
0298     saveIccProfile(mask, mask->colorSpace()->profile());
0299 
0300     m_store->popDirectory();
0301 
0302     return true;
0303 }
0304 
0305 QStringList KisKraSaveVisitor::errorMessages() const
0306 {
0307     return m_errorMessages;
0308 }
0309 
0310 struct SimpleDevicePolicy
0311 {
0312     bool write(KisPaintDeviceSP dev, KisPaintDeviceWriter &store) {
0313         return dev->write(store);
0314     }
0315 
0316     KoColor defaultPixel(KisPaintDeviceSP dev) const {
0317         return dev->defaultPixel();
0318     }
0319 };
0320 
0321 struct FramedDevicePolicy
0322 {
0323     FramedDevicePolicy(int frameId)
0324         :  m_frameId(frameId) {}
0325 
0326     bool write(KisPaintDeviceSP dev, KisPaintDeviceWriter &store) {
0327         return dev->framesInterface()->writeFrame(store, m_frameId);
0328     }
0329 
0330     KoColor defaultPixel(KisPaintDeviceSP dev) const {
0331         return dev->framesInterface()->frameDefaultPixel(m_frameId);
0332     }
0333 
0334     int m_frameId;
0335 };
0336 
0337 bool KisKraSaveVisitor::savePaintDevice(KisPaintDeviceSP device,
0338                                         QString location)
0339 {
0340     // Layer data
0341     KisConfig cfg(true);
0342     m_store->setCompressionEnabled(cfg.compressKra());
0343 
0344     KisPaintDeviceFramesInterface *frameInterface = device->framesInterface();
0345     QList<int> frames;
0346 
0347     if (frameInterface) {
0348         frames = frameInterface->frames();
0349     }
0350 
0351     if (!frameInterface || frames.count() <= 1) {
0352         savePaintDeviceFrame(device, location, SimpleDevicePolicy());
0353     } else {
0354         KisRasterKeyframeChannel *keyframeChannel = device->keyframeChannel();
0355 
0356         for (int i = 0; i < frames.count(); i++) {
0357             int id = frames[i];
0358 
0359             QString frameFilename = getLocation(keyframeChannel->frameFilename(id));
0360             Q_ASSERT(!frameFilename.isEmpty());
0361 
0362             if (!savePaintDeviceFrame(device, frameFilename, FramedDevicePolicy(id))) {
0363                 return false;
0364             }
0365         }
0366     }
0367 
0368     m_store->setCompressionEnabled(true);
0369     return true;
0370 }
0371 
0372 
0373 template<class DevicePolicy>
0374 bool KisKraSaveVisitor::savePaintDeviceFrame(KisPaintDeviceSP device, QString location, DevicePolicy policy)
0375 {
0376     if (m_store->open(location)) {
0377         if (!policy.write(device, *m_writer)) {
0378             device->disconnect();
0379             m_store->close();
0380             return false;
0381         }
0382 
0383         m_store->close();
0384     }
0385     if (m_store->open(location + ".defaultpixel")) {
0386         m_store->write((char*)policy.defaultPixel(device).data(), device->colorSpace()->pixelSize());
0387         m_store->close();
0388     }
0389 
0390     return true;
0391 }
0392 
0393 bool KisKraSaveVisitor::saveAnnotations(KisLayer* layer)
0394 {
0395     if (!layer) return false;
0396     if (!layer->paintDevice()) return false;
0397     if (!layer->paintDevice()->colorSpace()) return false;
0398 
0399     if (layer->paintDevice()->colorSpace()->profile()) {
0400         return saveIccProfile(layer, layer->paintDevice()->colorSpace()->profile());
0401     }
0402     return true;
0403 
0404 }
0405 
0406 bool KisKraSaveVisitor::saveIccProfile(KisNode *node, const KoColorProfile *profile)
0407 {
0408     if (profile) {
0409         KisAnnotationSP annotation;
0410         if (profile) {
0411             QByteArray profileRawData = profile->rawData();
0412             if (!profileRawData.isEmpty()) {
0413                 if (profile->type() == "icc") {
0414                     annotation = new KisAnnotation(ICC, profile->name(), profile->rawData());
0415                 } else {
0416                     annotation = new KisAnnotation(PROFILE, profile->name(), profile->rawData());
0417                 }
0418             }
0419         }
0420 
0421         if (annotation) {
0422             // save layer profile
0423             if (m_store->open(getLocation(node, DOT_ICC))) {
0424                 m_store->write(annotation->annotation());
0425                 m_store->close();
0426             } else {
0427                 return false;
0428             }
0429         }
0430     }
0431     return true;
0432 }
0433 
0434 bool KisKraSaveVisitor::saveSelection(KisNode* node)
0435 {
0436     KisSelectionSP selection;
0437     if (node->inherits("KisMask")) {
0438         selection = static_cast<KisMask*>(node)->selection();
0439     } else if (node->inherits("KisAdjustmentLayer")) {
0440         selection = static_cast<KisAdjustmentLayer*>(node)->internalSelection();
0441     } else if (node->inherits("KisGeneratorLayer")) {
0442         selection = static_cast<KisGeneratorLayer*>(node)->internalSelection();
0443     } else {
0444         return false;
0445     }
0446 
0447     bool retval = true;
0448 
0449     if (selection->hasNonEmptyPixelSelection()) {
0450         KisPaintDeviceSP dev = selection->pixelSelection();
0451         if (!savePaintDevice(dev, getLocation(node, DOT_PIXEL_SELECTION))) {
0452             m_errorMessages << i18n("Failed to save the pixel selection data for layer %1.", node->name());
0453             retval = false;
0454         }
0455     }
0456     if (selection->hasNonEmptyShapeSelection()) {
0457         m_store->pushDirectory();
0458         retval = m_store->enterDirectory(getLocation(node, DOT_SHAPE_SELECTION));
0459         if (retval) {
0460             KisShapeSelection* shapeSelection = dynamic_cast<KisShapeSelection*>(selection->shapeSelection());
0461             if (!shapeSelection) {
0462                 retval = false;
0463             }
0464 
0465             if (retval && !shapeSelection->saveSelection(m_store, node->image()->bounds())) {
0466                 m_errorMessages << i18n("Failed to save the vector selection data for layer %1.", node->name());
0467                 retval = false;
0468             }
0469         }
0470         m_store->popDirectory();
0471     }
0472     return retval;
0473 }
0474 
0475 bool KisKraSaveVisitor::saveFilterConfiguration(KisNode* node)
0476 {
0477     KisNodeFilterInterface *filterInterface =
0478             dynamic_cast<KisNodeFilterInterface*>(node);
0479 
0480     KisFilterConfigurationSP filter;
0481 
0482     if (filterInterface) {
0483         filter = filterInterface->filter();
0484     }
0485 
0486     bool retval = false;
0487 
0488     if (filter) {
0489         QString location = getLocation(node, DOT_FILTERCONFIG);
0490         if (m_store->open(location)) {
0491             QString s = filter->toXML();
0492             retval = (m_store->write(s.toUtf8(), qstrlen(s.toUtf8())) == qstrlen(s.toUtf8())); m_store->close();
0493         }
0494     }
0495     return retval;
0496 }
0497 
0498 bool KisKraSaveVisitor::saveMetaData(KisNode* node)
0499 {
0500     if (!node->inherits("KisLayer")) return true;
0501 
0502     KisMetaData::Store* metadata = (static_cast<KisLayer*>(node))->metaData();
0503     if (metadata->isEmpty()) return true;
0504 
0505     // Serialize all the types of metadata there are
0506     KisMetaData::IOBackend *backend = KisMetadataBackendRegistry::instance()->get("xmp");
0507     if (!backend->supportSaving()) {
0508         dbgFile << "Backend " << backend->id() << " does not support saving.";
0509         return false;
0510     }
0511 
0512     QString location = getLocation(node, QString(".") + backend->id() +  DOT_METADATA);
0513     dbgFile << "going to save " << backend->id() << ", " << backend->name() << " to " << location;
0514 
0515     QBuffer buffer;
0516     // not that the metadata backends every return anything but true...
0517     bool retval = backend->saveTo(metadata, &buffer);
0518 
0519     if (!retval) {
0520         m_errorMessages << i18n("The metadata backend failed to save the metadata for %1", node->name());
0521     }
0522     else {
0523         QByteArray data = buffer.data();
0524         dbgFile << "\t information size is" << data.size();
0525 
0526         if (data.size() > 0 && m_store->open(location)) {
0527             retval = m_store->write(data,  data.size());
0528             m_store->close();
0529         }
0530         if (!retval) {
0531             m_errorMessages << i18n("Could not write for %1 metadata to the file.", node->name());
0532         }
0533     }
0534     return retval;
0535 }
0536 
0537 QString KisKraSaveVisitor::getLocation(KisNode* node, const QString& suffix)
0538 {
0539 
0540     Q_ASSERT(m_nodeFileNames.contains(node));
0541     return getLocation(m_nodeFileNames[node], suffix);
0542 }
0543 
0544 QString KisKraSaveVisitor::getLocation(const QString &filename, const QString& suffix)
0545 {
0546     QString location = m_external ? QString() : m_uri;
0547     location += m_name + LAYER_PATH + filename + suffix;
0548     return location;
0549 }