File indexing completed on 2024-05-12 15:59:05

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 #include "Document.h"
0007 #include <QPointer>
0008 #include <QUrl>
0009 #include <QDomDocument>
0010 
0011 #include <KoColorSpaceConstants.h>
0012 #include <KisDocument.h>
0013 #include <kis_image.h>
0014 #include <KisPart.h>
0015 #include <kis_paint_device.h>
0016 #include <KisMainWindow.h>
0017 #include <kis_node_manager.h>
0018 #include <kis_node_selection_adapter.h>
0019 #include <KisViewManager.h>
0020 #include <kis_file_layer.h>
0021 #include <kis_adjustment_layer.h>
0022 #include <kis_mask.h>
0023 #include <kis_clone_layer.h>
0024 #include <kis_group_layer.h>
0025 #include <kis_filter_mask.h>
0026 #include <kis_transform_mask.h>
0027 #include <kis_transparency_mask.h>
0028 #include <kis_selection_mask.h>
0029 #include <kis_effect_mask.h>
0030 #include <kis_paint_layer.h>
0031 #include <kis_generator_layer.h>
0032 #include <kis_generator_registry.h>
0033 #include <kis_shape_layer.h>
0034 #include <kis_filter_configuration.h>
0035 #include <kis_filter_registry.h>
0036 #include <kis_selection.h>
0037 #include <KisMimeDatabase.h>
0038 #include <kis_filter_strategy.h>
0039 #include <kis_guides_config.h>
0040 #include <kis_coordinates_converter.h>
0041 #include <kis_time_span.h>
0042 #include <KisImportExportErrorCode.h>
0043 #include <kis_types.h>
0044 #include <kis_annotation.h>
0045 
0046 #include <KoColor.h>
0047 #include <KoColorSpace.h>
0048 #include <KoColorProfile.h>
0049 #include <KoColorSpaceRegistry.h>
0050 #include <KoColorConversionTransformation.h>
0051 #include <KoDocumentInfo.h>
0052 #include <KisGlobalResourcesInterface.h>
0053 
0054 #include <InfoObject.h>
0055 #include <Node.h>
0056 #include <Selection.h>
0057 #include <LibKisUtils.h>
0058 
0059 #include "kis_animation_importer.h"
0060 #include <kis_canvas2.h>
0061 #include <KoUpdater.h>
0062 #include <QMessageBox>
0063 
0064 #include <kis_image_animation_interface.h>
0065 
0066 struct Document::Private {
0067     Private() {}
0068     QPointer<KisDocument> document;
0069     bool ownsDocument {false};
0070 };
0071 
0072 Document::Document(KisDocument *document, bool ownsDocument, QObject *parent)
0073     : QObject(parent)
0074     , d(new Private)
0075 {
0076     d->document = document;
0077     d->ownsDocument = ownsDocument;
0078 }
0079 
0080 Document::~Document()
0081 {
0082     if (d->ownsDocument && d->document) {
0083         KisPart::instance()->removeDocument(d->document);
0084         delete d->document;
0085     }
0086     delete d;
0087 }
0088 
0089 bool Document::operator==(const Document &other) const
0090 {
0091     return (d->document == other.d->document);
0092 }
0093 
0094 bool Document::operator!=(const Document &other) const
0095 {
0096     return !(operator==(other));
0097 }
0098 
0099 bool Document::batchmode() const
0100 {
0101     if (!d->document) return false;
0102     return d->document->fileBatchMode();
0103 }
0104 
0105 void Document::setBatchmode(bool value)
0106 {
0107     if (!d->document) return;
0108     d->document->setFileBatchMode(value);
0109 }
0110 
0111 Node *Document::activeNode() const
0112 {
0113     QList<KisNodeSP> activeNodes;
0114     Q_FOREACH(QPointer<KisView> view, KisPart::instance()->views()) {
0115         if (view && view->document() == d->document) {
0116             activeNodes << view->currentNode();
0117 
0118         }
0119     }
0120     if (activeNodes.size() > 0) {
0121         QList<Node*> nodes = LibKisUtils::createNodeList(activeNodes, d->document->image());
0122         return nodes.first();
0123     }
0124 
0125     return 0;
0126 }
0127 
0128 void Document::setActiveNode(Node* value)
0129 {
0130     if (!value->node()) return;
0131     KisMainWindow *mainWin = KisPart::instance()->currentMainwindow();
0132     if (!mainWin) return;
0133     KisViewManager *viewManager = mainWin->viewManager();
0134     if (!viewManager) return;
0135     if (viewManager->document() != d->document) return;
0136     KisNodeManager *nodeManager = viewManager->nodeManager();
0137     if (!nodeManager) return;
0138     KisNodeSelectionAdapter *selectionAdapter = nodeManager->nodeSelectionAdapter();
0139     if (!selectionAdapter) return;
0140     selectionAdapter->setActiveNode(value->node());
0141 
0142 }
0143 
0144 QList<Node *> Document::topLevelNodes() const
0145 {
0146     if (!d->document) return QList<Node *>();
0147     Node n(d->document->image(), d->document->image()->rootLayer());
0148     return n.childNodes();
0149 }
0150 
0151 
0152 Node *Document::nodeByName(const QString &name) const
0153 {
0154     if (!d->document) return 0;
0155     KisNodeSP node = d->document->image()->rootLayer()->findChildByName(name);
0156     if (node.isNull()) return 0;
0157     return Node::createNode(d->document->image(), node);
0158 }
0159 
0160 Node *Document::nodeByUniqueID(const QUuid &id) const
0161 {
0162     if (!d->document) return 0;
0163     KisNodeSP node = d->document->image()->rootLayer()->findChildByUniqueID(id);
0164     if (node.isNull()) return 0;
0165     return Node::createNode(d->document->image(), node);
0166 }
0167 
0168 
0169 QString Document::colorDepth() const
0170 {
0171     if (!d->document) return "";
0172     return d->document->image()->colorSpace()->colorDepthId().id();
0173 }
0174 
0175 QString Document::colorModel() const
0176 {
0177     if (!d->document) return "";
0178     return d->document->image()->colorSpace()->colorModelId().id();
0179 }
0180 
0181 QString Document::colorProfile() const
0182 {
0183     if (!d->document) return "";
0184     return d->document->image()->colorSpace()->profile()->name();
0185 }
0186 
0187 bool Document::setColorProfile(const QString &value)
0188 {
0189     if (!d->document) return false;
0190     if (!d->document->image()) return false;
0191     const KoColorProfile *profile = KoColorSpaceRegistry::instance()->profileByName(value);
0192     if (!profile) return false;
0193     bool retval = d->document->image()->assignImageProfile(profile);
0194     d->document->image()->waitForDone();
0195     return retval;
0196 }
0197 
0198 bool Document::setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile)
0199 {
0200     if (!d->document) return false;
0201     if (!d->document->image()) return false;
0202     const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, colorProfile);
0203     if (!colorSpace) return false;
0204 
0205     d->document->image()->convertImageColorSpace(colorSpace,
0206                                                  KoColorConversionTransformation::IntentPerceptual,
0207                                                  KoColorConversionTransformation::HighQuality | KoColorConversionTransformation::NoOptimization);
0208 
0209     d->document->image()->waitForDone();
0210     return true;
0211 }
0212 
0213 QColor Document::backgroundColor()
0214 {
0215     if (!d->document) return QColor();
0216     if (!d->document->image()) return QColor();
0217 
0218     const KoColor color = d->document->image()->defaultProjectionColor();
0219     return color.toQColor();
0220 }
0221 
0222 bool Document::setBackgroundColor(const QColor &color)
0223 {
0224     if (!d->document) return false;
0225     if (!d->document->image()) return false;
0226 
0227     KoColor background = KoColor(color, d->document->image()->colorSpace());
0228     d->document->image()->setDefaultProjectionColor(background);
0229 
0230     d->document->image()->setModifiedWithoutUndo();
0231     d->document->image()->initialRefreshGraph();
0232 
0233     return true;
0234 }
0235 
0236 QString Document::documentInfo() const
0237 {
0238     QDomDocument doc = KisDocument::createDomDocument("document-info"
0239                                                       /*DTD name*/, "document-info" /*tag name*/, "1.1");
0240     doc = d->document->documentInfo()->save(doc);
0241     return doc.toString();
0242 }
0243 
0244 void Document::setDocumentInfo(const QString &document)
0245 {
0246     QDomDocument doc;
0247     QString errorMsg;
0248     int errorLine, errorColumn;
0249     doc.setContent(document, &errorMsg, &errorLine, &errorColumn);
0250     d->document->documentInfo()->load(doc);
0251 }
0252 
0253 
0254 QString Document::fileName() const
0255 {
0256     if (!d->document) return QString();
0257     return d->document->path();
0258 }
0259 
0260 void Document::setFileName(QString value)
0261 {
0262     if (!d->document) return;
0263     QString mimeType = KisMimeDatabase::mimeTypeForFile(value, false);
0264     d->document->setMimeType(mimeType.toLatin1());
0265     d->document->setPath(value);
0266 }
0267 
0268 int Document::height() const
0269 {
0270     if (!d->document) return 0;
0271     KisImageSP image = d->document->image();
0272     if (!image) return 0;
0273     return image->height();
0274 }
0275 
0276 void Document::setHeight(int value)
0277 {
0278     if (!d->document) return;
0279     if (!d->document->image()) return;
0280     resizeImage(d->document->image()->bounds().x(),
0281                 d->document->image()->bounds().y(),
0282                 d->document->image()->width(),
0283                 value);
0284 }
0285 
0286 
0287 QString Document::name() const
0288 {
0289     if (!d->document) return "";
0290     return d->document->documentInfo()->aboutInfo("title");
0291 }
0292 
0293 void Document::setName(QString value)
0294 {
0295     if (!d->document) return;
0296     d->document->documentInfo()->setAboutInfo("title", value);
0297 }
0298 
0299 
0300 int Document::resolution() const
0301 {
0302     if (!d->document) return 0;
0303     KisImageSP image = d->document->image();
0304     if (!image) return 0;
0305 
0306     return qRound(d->document->image()->xRes() * 72);
0307 }
0308 
0309 void Document::setResolution(int value)
0310 {
0311     if (!d->document) return;
0312     KisImageSP image = d->document->image();
0313     if (!image) return;
0314 
0315     KisFilterStrategy *strategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
0316     KIS_SAFE_ASSERT_RECOVER_RETURN(strategy);
0317 
0318     image->scaleImage(image->size(), value / 72.0, value / 72.0, strategy);
0319     image->waitForDone();
0320 }
0321 
0322 
0323 Node *Document::rootNode() const
0324 {
0325     if (!d->document) return 0;
0326     KisImageSP image = d->document->image();
0327     if (!image) return 0;
0328 
0329     return Node::createNode(image, image->root());
0330 }
0331 
0332 Selection *Document::selection() const
0333 {
0334     if (!d->document) return 0;
0335     if (!d->document->image()) return 0;
0336     if (!d->document->image()->globalSelection()) return 0;
0337     return new Selection(d->document->image()->globalSelection());
0338 }
0339 
0340 void Document::setSelection(Selection* value)
0341 {
0342     if (!d->document) return;
0343     if (!d->document->image()) return;
0344     if (value) {
0345         d->document->image()->setGlobalSelection(value->selection());
0346     }
0347     else {
0348         d->document->image()->setGlobalSelection(0);
0349     }
0350 }
0351 
0352 
0353 int Document::width() const
0354 {
0355     if (!d->document) return 0;
0356     KisImageSP image = d->document->image();
0357     if (!image) return 0;
0358     return image->width();
0359 }
0360 
0361 void Document::setWidth(int value)
0362 {
0363     if (!d->document) return;
0364     if (!d->document->image()) return;
0365     resizeImage(d->document->image()->bounds().x(),
0366                 d->document->image()->bounds().y(),
0367                 value,
0368                 d->document->image()->height());
0369 }
0370 
0371 
0372 int Document::xOffset() const
0373 {
0374     if (!d->document) return 0;
0375     KisImageSP image = d->document->image();
0376     if (!image) return 0;
0377     return image->bounds().x();
0378 }
0379 
0380 void Document::setXOffset(int x)
0381 {
0382     if (!d->document) return;
0383     if (!d->document->image()) return;
0384     resizeImage(x,
0385                 d->document->image()->bounds().y(),
0386                 d->document->image()->width(),
0387                 d->document->image()->height());
0388 }
0389 
0390 
0391 int Document::yOffset() const
0392 {
0393     if (!d->document) return 0;
0394     KisImageSP image = d->document->image();
0395     if (!image) return 0;
0396     return image->bounds().y();
0397 }
0398 
0399 void Document::setYOffset(int y)
0400 {
0401     if (!d->document) return;
0402     if (!d->document->image()) return;
0403     resizeImage(d->document->image()->bounds().x(),
0404                 y,
0405                 d->document->image()->width(),
0406                 d->document->image()->height());
0407 }
0408 
0409 
0410 double Document::xRes() const
0411 {
0412     if (!d->document) return 0.0;
0413     if (!d->document->image()) return 0.0;
0414     return d->document->image()->xRes()*72.0;
0415 }
0416 
0417 void Document::setXRes(double xRes) const
0418 {
0419     if (!d->document) return;
0420     KisImageSP image = d->document->image();
0421     if (!image) return;
0422 
0423     KisFilterStrategy *strategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
0424     KIS_SAFE_ASSERT_RECOVER_RETURN(strategy);
0425 
0426     image->scaleImage(image->size(), xRes / 72.0, image->yRes(), strategy);
0427     image->waitForDone();
0428 }
0429 
0430 double Document::yRes() const
0431 {
0432     if (!d->document) return 0.0;
0433     if (!d->document->image()) return 0.0;
0434     return d->document->image()->yRes()*72.0;
0435 }
0436 
0437 void Document::setYRes(double yRes) const
0438 {
0439     if (!d->document) return;
0440     KisImageSP image = d->document->image();
0441     if (!image) return;
0442 
0443     KisFilterStrategy *strategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
0444     KIS_SAFE_ASSERT_RECOVER_RETURN(strategy);
0445 
0446     image->scaleImage(image->size(), image->xRes(), yRes / 72.0, strategy);
0447     image->waitForDone();
0448 }
0449 
0450 
0451 QByteArray Document::pixelData(int x, int y, int w, int h) const
0452 {
0453     QByteArray ba;
0454 
0455     if (!d->document) return ba;
0456     KisImageSP image = d->document->image();
0457     if (!image) return ba;
0458 
0459     KisPaintDeviceSP dev = image->projection();
0460     ba.resize(w * h * dev->pixelSize());
0461     dev->readBytes(reinterpret_cast<quint8*>(ba.data()), x, y, w, h);
0462     return ba;
0463 }
0464 
0465 bool Document::close()
0466 {
0467     bool retval = d->document->closePath(false);
0468 
0469     Q_FOREACH(KisView *view, KisPart::instance()->views()) {
0470         if (view->document() == d->document) {
0471             view->close();
0472             view->closeView();
0473             view->deleteLater();
0474         }
0475     }
0476 
0477     KisPart::instance()->removeDocument(d->document, !d->ownsDocument);
0478 
0479     if (d->ownsDocument) {
0480 
0481         delete d->document;
0482     }
0483 
0484     d->document = 0;
0485     return retval;
0486 }
0487 
0488 void Document::crop(int x, int y, int w, int h)
0489 {
0490     if (!d->document) return;
0491     KisImageSP image = d->document->image();
0492     if (!image) return;
0493     QRect rc(x, y, w, h);
0494     image->cropImage(rc);
0495     image->waitForDone();
0496 }
0497 
0498 bool Document::exportImage(const QString &filename, const InfoObject &exportConfiguration)
0499 {
0500     if (!d->document) return false;
0501 
0502     const QString outputFormatString = KisMimeDatabase::mimeTypeForFile(filename, false);
0503     const QByteArray outputFormat = outputFormatString.toLatin1();
0504 
0505     return d->document->exportDocumentSync(filename, outputFormat, exportConfiguration.configuration());
0506 }
0507 
0508 void Document::flatten()
0509 {
0510     if (!d->document) return;
0511     if (!d->document->image()) return;
0512     d->document->image()->flatten(0);
0513     d->document->image()->waitForDone();
0514 }
0515 
0516 void Document::resizeImage(int x, int y, int w, int h)
0517 {
0518     if (!d->document) return;
0519     KisImageSP image = d->document->image();
0520     if (!image) return;
0521     QRect rc;
0522     rc.setX(x);
0523     rc.setY(y);
0524     rc.setWidth(w);
0525     rc.setHeight(h);
0526 
0527     image->resizeImage(rc);
0528     image->waitForDone();
0529 }
0530 
0531 void Document::scaleImage(int w, int h, int xres, int yres, QString strategy)
0532 {
0533     if (!d->document) return;
0534     KisImageSP image = d->document->image();
0535     if (!image) return;
0536     QRect rc = image->bounds();
0537     rc.setWidth(w);
0538     rc.setHeight(h);
0539 
0540     KisFilterStrategy *actualStrategy = KisFilterStrategyRegistry::instance()->get(strategy);
0541     if (!actualStrategy) actualStrategy = KisFilterStrategyRegistry::instance()->get("Bicubic");
0542 
0543     image->scaleImage(rc.size(), xres/72, yres/72, actualStrategy);
0544     image->waitForDone();
0545 }
0546 
0547 void Document::rotateImage(double radians)
0548 {
0549     if (!d->document) return;
0550     KisImageSP image = d->document->image();
0551     if (!image) return;
0552     image->rotateImage(radians);
0553     image->waitForDone();
0554 }
0555 
0556 void Document::shearImage(double angleX, double angleY)
0557 {
0558     if (!d->document) return;
0559     KisImageSP image = d->document->image();
0560     if (!image) return;
0561     image->shear(angleX, angleY);
0562     image->waitForDone();
0563 }
0564 
0565 bool Document::save()
0566 {
0567     if (!d->document) return false;
0568     if (d->document->path().isEmpty()) return false;
0569 
0570     bool retval = d->document->save(true, 0);
0571     d->document->waitForSavingToComplete();
0572 
0573     return retval;
0574 }
0575 
0576 bool Document::saveAs(const QString &filename)
0577 {
0578     if (!d->document) return false;
0579 
0580     setFileName(filename);
0581     const QString outputFormatString = KisMimeDatabase::mimeTypeForFile(filename, false);
0582     const QByteArray outputFormat = outputFormatString.toLatin1();
0583     QString oldPath = d->document->path();
0584     d->document->setPath(filename);
0585     bool retval = d->document->saveAs(filename, outputFormat, true);
0586     d->document->waitForSavingToComplete();
0587     d->document->setPath(oldPath);
0588 
0589     return retval;
0590 }
0591 
0592 Node* Document::createNode(const QString &name, const QString &nodeType)
0593 {
0594     if (!d->document) return 0;
0595     if (!d->document->image()) return 0;
0596     KisImageSP image = d->document->image();
0597 
0598     Node *node = 0;
0599 
0600     if (nodeType.toLower()== "paintlayer") {
0601         node = new Node(image, new KisPaintLayer(image, name, OPACITY_OPAQUE_U8));
0602     }
0603     else if (nodeType.toLower()  == "grouplayer") {
0604         node = new Node(image, new KisGroupLayer(image, name, OPACITY_OPAQUE_U8));
0605     }
0606     else if (nodeType.toLower()  == "filelayer") {
0607         node = new Node(image, new KisFileLayer(image, name, OPACITY_OPAQUE_U8));
0608     }
0609     else if (nodeType.toLower()  == "filterlayer") {
0610         node = new Node(image, new KisAdjustmentLayer(image, name, 0, 0));
0611     }
0612     else if (nodeType.toLower()  == "filllayer") {
0613         node = new Node(image, new KisGeneratorLayer(image, name, 0, 0));
0614     }
0615     else if (nodeType.toLower()  == "clonelayer") {
0616         node = new Node(image, new KisCloneLayer(0, image, name, OPACITY_OPAQUE_U8));
0617     }
0618     else if (nodeType.toLower()  == "vectorlayer") {
0619         node = new Node(image, new KisShapeLayer(d->document->shapeController(), image, name, OPACITY_OPAQUE_U8));
0620     }
0621     else if (nodeType.toLower()  == "transparencymask") {
0622         node = new Node(image, new KisTransparencyMask(image, name));
0623     }
0624     else if (nodeType.toLower()  == "filtermask") {
0625         node = new Node(image, new KisFilterMask(image, name));
0626     }
0627     else if (nodeType.toLower()  == "transformmask") {
0628         node = new Node(image, new KisTransformMask(image, name));
0629     }
0630     else if (nodeType.toLower()  == "selectionmask") {
0631         node = new Node(image, new KisSelectionMask(image, name));
0632     }
0633 
0634     return node;
0635 }
0636 
0637 GroupLayer *Document::createGroupLayer(const QString &name)
0638 {
0639     if (!d->document) return 0;
0640     if (!d->document->image()) return 0;
0641     KisImageSP image = d->document->image();
0642 
0643     return new GroupLayer(image, name);
0644 }
0645 
0646 FileLayer *Document::createFileLayer(const QString &name, const QString fileName, const QString scalingMethod)
0647 {
0648     if (!d->document) return 0;
0649     if (!d->document->image()) return 0;
0650     KisImageSP image = d->document->image();
0651 
0652     return new FileLayer(image, name, this->fileName(), fileName, scalingMethod);
0653 }
0654 
0655 FilterLayer *Document::createFilterLayer(const QString &name, Filter &filter, Selection &selection)
0656 {
0657     if (!d->document) return 0;
0658     if (!d->document->image()) return 0;
0659     KisImageSP image = d->document->image();
0660 
0661     return new FilterLayer(image, name, filter, selection);
0662 }
0663 
0664 FillLayer *Document::createFillLayer(const QString &name, const QString generatorName, InfoObject &configuration, Selection &selection)
0665 {
0666     if (!d->document) return 0;
0667     if (!d->document->image()) return 0;
0668     KisImageSP image = d->document->image();
0669 
0670     KisGeneratorSP generator = KisGeneratorRegistry::instance()->value(generatorName);
0671     if (generator) {
0672 
0673         KisFilterConfigurationSP config = generator->factoryConfiguration(KisGlobalResourcesInterface::instance());
0674         Q_FOREACH(const QString property, configuration.properties().keys()) {
0675             config->setProperty(property, configuration.property(property));
0676         }
0677 
0678         return new FillLayer(image, name, config, selection);
0679     }
0680     return 0;
0681 }
0682 
0683 CloneLayer *Document::createCloneLayer(const QString &name, const Node *source)
0684 {
0685     if (!d->document) return 0;
0686     if (!d->document->image()) return 0;
0687     KisImageSP image = d->document->image();
0688     KisLayerSP layer = qobject_cast<KisLayer*>(source->node().data());
0689 
0690     return new CloneLayer(image, name, layer);
0691 }
0692 
0693 VectorLayer *Document::createVectorLayer(const QString &name)
0694 {
0695     if (!d->document) return 0;
0696     if (!d->document->image()) return 0;
0697     KisImageSP image = d->document->image();
0698 
0699     return new VectorLayer(d->document->shapeController(), image, name);
0700 }
0701 
0702 FilterMask *Document::createFilterMask(const QString &name, Filter &filter, const Node *selection_source)
0703 {
0704     if (!d->document)
0705         return 0;
0706 
0707     if (!d->document->image())
0708         return 0;
0709 
0710     if(!selection_source)
0711         return 0;
0712 
0713     KisLayerSP layer = qobject_cast<KisLayer*>(selection_source->node().data());
0714     if(layer.isNull())
0715         return 0;
0716 
0717     KisImageSP image = d->document->image();
0718     FilterMask* mask = new FilterMask(image, name, filter);
0719     qobject_cast<KisMask*>(mask->node().data())->initSelection(layer);
0720 
0721     return mask;
0722 }
0723 
0724 FilterMask *Document::createFilterMask(const QString &name, Filter &filter, Selection &selection)
0725 {
0726     if (!d->document)
0727         return 0;
0728 
0729     if (!d->document->image())
0730         return 0;
0731 
0732     KisImageSP image = d->document->image();
0733     FilterMask* mask = new FilterMask(image, name, filter);
0734     qobject_cast<KisMask*>(mask->node().data())->setSelection(selection.selection());
0735 
0736     return mask;
0737 }
0738 
0739 SelectionMask *Document::createSelectionMask(const QString &name)
0740 {
0741     if (!d->document) return 0;
0742     if (!d->document->image()) return 0;
0743     KisImageSP image = d->document->image();
0744 
0745     return new SelectionMask(image, name);
0746 }
0747 
0748 TransformMask *Document::createTransformMask(const QString &name)
0749 {
0750     if (!d->document) return 0;
0751     if (!d->document->image()) return 0;
0752     KisImageSP image = d->document->image();
0753 
0754     return new TransformMask(image, name);
0755 }
0756 
0757 QImage Document::projection(int x, int y, int w, int h) const
0758 {
0759     if (!d->document || !d->document->image()) return QImage();
0760     return d->document->image()->convertToQImage(x, y, w, h, 0);
0761 }
0762 
0763 QImage Document::thumbnail(int w, int h) const
0764 {
0765     if (!d->document || !d->document->image()) return QImage();
0766     return d->document->generatePreview(QSize(w, h)).toImage();
0767 }
0768 
0769 
0770 void Document::lock()
0771 {
0772     if (!d->document || !d->document->image()) return;
0773     d->document->image()->barrierLock();
0774 }
0775 
0776 void Document::unlock()
0777 {
0778     if (!d->document || !d->document->image()) return;
0779     d->document->image()->unlock();
0780 }
0781 
0782 void Document::waitForDone()
0783 {
0784     if (!d->document || !d->document->image()) return;
0785     d->document->image()->waitForDone();
0786 }
0787 
0788 bool Document::tryBarrierLock()
0789 {
0790     if (!d->document || !d->document->image()) return false;
0791     return d->document->image()->tryBarrierLock();
0792 }
0793 
0794 void Document::refreshProjection()
0795 {
0796     if (!d->document || !d->document->image()) return;
0797     d->document->image()->refreshGraph();
0798 }
0799 
0800 QList<qreal> Document::horizontalGuides() const
0801 {
0802     QList<qreal> lines;
0803     if (!d->document || !d->document->image()) return lines;
0804     KisCoordinatesConverter converter;
0805     converter.setImage(d->document->image());
0806     QTransform transform = converter.imageToDocumentTransform().inverted();
0807     QList<qreal> untransformedLines = d->document->guidesConfig().horizontalGuideLines();
0808     for (int i = 0; i< untransformedLines.size(); i++) {
0809         qreal line = untransformedLines[i];
0810         lines.append(transform.map(QPointF(line, line)).x());
0811     }
0812     return lines;
0813 }
0814 
0815 QList<qreal> Document::verticalGuides() const
0816 {
0817     QList<qreal> lines;
0818     if (!d->document || !d->document->image()) return lines;
0819     KisCoordinatesConverter converter;
0820     converter.setImage(d->document->image());
0821     QTransform transform = converter.imageToDocumentTransform().inverted();
0822     QList<qreal> untransformedLines = d->document->guidesConfig().verticalGuideLines();
0823     for (int i = 0; i< untransformedLines.size(); i++) {
0824         qreal line = untransformedLines[i];
0825         lines.append(transform.map(QPointF(line, line)).y());
0826     }
0827     return lines;
0828 }
0829 
0830 bool Document::guidesVisible() const
0831 {
0832     return d->document->guidesConfig().showGuides();
0833 }
0834 
0835 bool Document::guidesLocked() const
0836 {
0837     return d->document->guidesConfig().lockGuides();
0838 }
0839 
0840 Document *Document::clone() const
0841 {
0842     if (!d->document) return 0;
0843     QPointer<KisDocument> clone = d->document->clone();
0844 
0845     /// We set ownsDocument to true, it will be reset
0846     /// automatically as soon as we create the first
0847     /// view for the document
0848     Document * newDocument = new Document(clone, true);
0849     return newDocument;
0850 }
0851 
0852 void Document::setHorizontalGuides(const QList<qreal> &lines)
0853 {
0854     if (!d->document) return;
0855     KisGuidesConfig config = d->document->guidesConfig();
0856     KisCoordinatesConverter converter;
0857     converter.setImage(d->document->image());
0858     QTransform transform = converter.imageToDocumentTransform();
0859     QList<qreal> transformedLines;
0860     for (int i = 0; i< lines.size(); i++) {
0861         qreal line = lines[i];
0862         transformedLines.append(transform.map(QPointF(line, line)).x());
0863     }
0864     config.setHorizontalGuideLines(transformedLines);
0865     d->document->setGuidesConfig(config);
0866 }
0867 
0868 void Document::setVerticalGuides(const QList<qreal> &lines)
0869 {
0870     if (!d->document) return;
0871     KisGuidesConfig config = d->document->guidesConfig();
0872     KisCoordinatesConverter converter;
0873     converter.setImage(d->document->image());
0874     QTransform transform = converter.imageToDocumentTransform();
0875     QList<qreal> transformedLines;
0876     for (int i = 0; i< lines.size(); i++) {
0877         qreal line = lines[i];
0878         transformedLines.append(transform.map(QPointF(line, line)).y());
0879     }
0880     config.setVerticalGuideLines(transformedLines);
0881     d->document->setGuidesConfig(config);
0882 }
0883 
0884 void Document::setGuidesVisible(bool visible)
0885 {
0886     if (!d->document) return;
0887     KisGuidesConfig config = d->document->guidesConfig();
0888     config.setShowGuides(visible);
0889     d->document->setGuidesConfig(config);
0890 }
0891 
0892 void Document::setGuidesLocked(bool locked)
0893 {
0894     if (!d->document) return;
0895     KisGuidesConfig config = d->document->guidesConfig();
0896     config.setLockGuides(locked);
0897     d->document->setGuidesConfig(config);
0898 }
0899 
0900 bool Document::modified() const
0901 {
0902     if (!d->document) return false;
0903     return d->document->isModified();
0904 }
0905 
0906 void Document::setModified(bool modified)
0907 {
0908     if (!d->document) return;
0909     d->document->setModified(modified);
0910 }
0911 
0912 QRect Document::bounds() const
0913 {
0914     if (!d->document) return QRect();
0915     return d->document->image()->bounds();
0916 }
0917 
0918 QPointer<KisDocument> Document::document() const
0919 {
0920     return d->document;
0921 }
0922 
0923 void Document::setOwnsDocument(bool ownsDocument)
0924 {
0925     d->ownsDocument = ownsDocument;
0926 }
0927 
0928 /* Animation related function */
0929 
0930 bool Document::importAnimation(const QList<QString> &files, int firstFrame, int step)
0931 {
0932     KisView *activeView = KisPart::instance()->currentMainwindow()->activeView();
0933 
0934     KoUpdaterPtr updater = 0;
0935     if (activeView && d->document->fileBatchMode()) {
0936          updater = activeView->viewManager()->createUnthreadedUpdater(i18n("Import frames"));
0937     }
0938 
0939     KisAnimationImporter importer(d->document->image(), updater);
0940     KisImportExportErrorCode status = importer.import(files, firstFrame, step);
0941 
0942     return status.isOk();
0943 }
0944 
0945 int Document::framesPerSecond()
0946 {
0947     if (!d->document) return false;
0948     if (!d->document->image()) return false;
0949 
0950     return d->document->image()->animationInterface()->framerate();
0951 }
0952 
0953 void Document::setFramesPerSecond(int fps)
0954 {
0955     if (!d->document) return;
0956     if (!d->document->image()) return;
0957 
0958     d->document->image()->animationInterface()->setFramerate(fps);
0959 }
0960 
0961 void Document::setFullClipRangeStartTime(int startTime)
0962 {
0963     if (!d->document) return;
0964     if (!d->document->image()) return;
0965 
0966     d->document->image()->animationInterface()->setFullClipRangeStartTime(startTime);
0967 }
0968 
0969 
0970 int Document::fullClipRangeStartTime()
0971 {
0972     if (!d->document) return false;
0973     if (!d->document->image()) return false;
0974 
0975     return d->document->image()->animationInterface()->fullClipRange().start();
0976 }
0977 
0978 
0979 void Document::setFullClipRangeEndTime(int endTime)
0980 {
0981     if (!d->document) return;
0982     if (!d->document->image()) return;
0983 
0984     d->document->image()->animationInterface()->setFullClipRangeEndTime(endTime);
0985 }
0986 
0987 
0988 int Document::fullClipRangeEndTime()
0989 {
0990     if (!d->document) return false;
0991     if (!d->document->image()) return false;
0992 
0993     return d->document->image()->animationInterface()->fullClipRange().end();
0994 }
0995 
0996 int Document::animationLength()
0997 {
0998     if (!d->document) return false;
0999     if (!d->document->image()) return false;
1000 
1001     return d->document->image()->animationInterface()->totalLength();
1002 }
1003 
1004 void Document::setPlayBackRange(int start, int stop)
1005 {
1006     if (!d->document) return;
1007     if (!d->document->image()) return;
1008 
1009     const KisTimeSpan newTimeRange = KisTimeSpan::fromTimeWithDuration(start, (stop-start));
1010     d->document->image()->animationInterface()->setPlaybackRange(newTimeRange);
1011 }
1012 
1013 int Document::playBackStartTime()
1014 {
1015     if (!d->document) return false;
1016     if (!d->document->image()) return false;
1017 
1018     return d->document->image()->animationInterface()->playbackRange().start();
1019 }
1020 
1021 int Document::playBackEndTime()
1022 {
1023     if (!d->document) return false;
1024     if (!d->document->image()) return false;
1025 
1026     return d->document->image()->animationInterface()->playbackRange().end();
1027 }
1028 
1029 int Document::currentTime()
1030 {
1031     if (!d->document) return false;
1032     if (!d->document->image()) return false;
1033 
1034     return d->document->image()->animationInterface()->currentTime();
1035 }
1036 
1037 void Document::setCurrentTime(int time)
1038 {
1039     if (!d->document) return;
1040     if (!d->document->image()) return;
1041 
1042     return d->document->image()->animationInterface()->requestTimeSwitchWithUndo(time);
1043 }
1044 
1045 QStringList Document::annotationTypes() const
1046 {
1047     if (!d->document) return QStringList();
1048 
1049     QStringList types;
1050 
1051     KisImageSP image = d->document->image().toStrongRef();
1052 
1053     if (!image) return QStringList();
1054 
1055     vKisAnnotationSP_it beginIt = image->beginAnnotations();
1056     vKisAnnotationSP_it endIt = image->endAnnotations();
1057 
1058     vKisAnnotationSP_it it = beginIt;
1059     while (it != endIt) {
1060         if (!(*it) || (*it)->type().isEmpty()) {
1061             qWarning() << "Warning: empty annotation";
1062             it++;
1063             continue;
1064         }
1065         types << (*it)->type();
1066 
1067         it++;
1068     }
1069     return types;
1070 }
1071 
1072 QString Document::annotationDescription(const QString &type) const
1073 {
1074     KisImageSP image = d->document->image().toStrongRef();
1075     KisAnnotationSP annotation = image->annotation(type);
1076     return annotation->description();
1077 }
1078 
1079 QByteArray Document::annotation(const QString &type)
1080 {
1081     KisImageSP image = d->document->image().toStrongRef();
1082     KisAnnotationSP annotation = image->annotation(type);
1083     if (annotation) {
1084         return annotation->annotation();
1085     }
1086     else {
1087         return QByteArray();
1088     }
1089 }
1090 
1091 void Document::setAnnotation(const QString &key, const QString &description, const QByteArray &annotation)
1092 {
1093     KisAnnotation *a = new KisAnnotation(key, description, annotation);
1094     KisImageSP image = d->document->image().toStrongRef();
1095     image->addAnnotation(a);
1096 
1097 }
1098 
1099 void Document::removeAnnotation(const QString &type)
1100 {
1101     KisImageSP image = d->document->image().toStrongRef();
1102     image->removeAnnotation(type);
1103 }