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