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 }