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

0001 /*
0002  *  SPDX-FileCopyrightText: 2017 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 #include "VectorLayer.h"
0007 #include <kis_shape_layer.h>
0008 #include <kis_image.h>
0009 #include <SvgWriter.h>
0010 #include <SvgParser.h>
0011 #include <QBuffer>
0012 #include <commands/KoShapeCreateCommand.h>
0013 #include <KoShapeGroup.h>
0014 #include <KisDocument.h>
0015 #include <kis_processing_applicator.h>
0016 
0017 #include "Krita.h"
0018 #include "GroupShape.h"
0019 
0020 VectorLayer::VectorLayer(KoShapeControllerBase* shapeController, KisImageSP image, QString name, QObject *parent) :
0021     Node(image, new KisShapeLayer(shapeController, image, name, OPACITY_OPAQUE_U8), parent)
0022 {
0023 
0024 }
0025 
0026 VectorLayer::VectorLayer(KisShapeLayerSP layer, QObject *parent):
0027     Node(layer->image(), layer, parent)
0028 {
0029 
0030 }
0031 
0032 VectorLayer::~VectorLayer()
0033 {
0034 
0035 }
0036 
0037 QString VectorLayer::type() const
0038 {
0039     return "vectorlayer";
0040 }
0041 
0042 QList<Shape *> VectorLayer::shapes() const
0043 {
0044     QList<Shape*> shapes;
0045     KisShapeLayerSP vector = KisShapeLayerSP(dynamic_cast<KisShapeLayer*>(this->node().data()));
0046     if (vector) {
0047         QList<KoShape*> originalShapes = vector->shapes();
0048         std::sort(originalShapes.begin(), originalShapes.end(), KoShape::compareShapeZIndex);
0049         for (int i=0; i<vector->shapeCount(); i++) {
0050             if (dynamic_cast<KoShapeGroup*>(originalShapes.at(i))) {
0051                 shapes << new GroupShape(dynamic_cast<KoShapeGroup*>(originalShapes.at(i)));
0052             } else {
0053                 shapes << new Shape(originalShapes.at(i));
0054             }
0055         }
0056     }
0057     return shapes;
0058 }
0059 
0060 QString VectorLayer::toSvg()
0061 {
0062     QString svgData;
0063     KisShapeLayerSP vector = KisShapeLayerSP(dynamic_cast<KisShapeLayer*>(this->node().data()));
0064 
0065     if (vector) {
0066         QBuffer buffer;
0067         QList<KoShape*> originalShapes = vector->shapes();
0068 
0069         std::sort(originalShapes.begin(), originalShapes.end(), KoShape::compareShapeZIndex);
0070 
0071         const QSizeF sizeInPx = this->node()->image()->bounds().size();
0072         const QSizeF pageSize(sizeInPx.width() / this->node()->image()->xRes(),
0073                           sizeInPx.height() / this->node()->image()->yRes());
0074 
0075         buffer.open(QIODevice::WriteOnly);
0076 
0077         SvgWriter writer(originalShapes);
0078 
0079         writer.save(buffer, pageSize);
0080         buffer.close();
0081 
0082         svgData = QString::fromUtf8(buffer.data());
0083     }
0084 
0085     return svgData;
0086 
0087 }
0088 
0089 QList<Shape *> VectorLayer::addShapesFromSvg(const QString &svgData)
0090 {
0091     QList<Shape*> shapes;
0092     QList<KoShape*> originalShapes;
0093 
0094     if (svgData.isEmpty() || !svgData.contains("<svg") ) {
0095         return shapes;
0096     }
0097 
0098     KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(this->node().data());
0099 
0100     if (container) {
0101         QSizeF fragmentSize;
0102         QString errorMsg;
0103         int errorLine = 0;
0104         int errorColumn = 0;
0105 
0106         QDomDocument dom = SvgParser::createDocumentFromSvg(svgData, &errorMsg, &errorLine, &errorColumn);
0107 
0108         if (dom.isNull()) {
0109             qWarning() << "Failed to process an SVG string at"
0110                        << errorLine << ":" << errorColumn << "->" << errorMsg;
0111             return shapes;
0112         }
0113 
0114         Document *document = Krita::instance()->activeDocument();
0115         SvgParser parser(document->document()->shapeController()->resourceManager());
0116 
0117         parser.setResolution(this->node()->image()->bounds(), this->node()->image()->xRes() * 72.0);
0118 
0119         originalShapes = parser.parseSvg(dom.documentElement(), &fragmentSize);
0120 
0121         KUndo2Command *cmd = new KoShapeCreateCommand(document->document()->shapeController(), originalShapes, container);
0122 
0123         KisProcessingApplicator::runSingleCommandStroke(this->node()->image(), cmd);
0124         this->node()->image()->waitForDone();
0125         delete document;
0126 
0127         std::sort(originalShapes.begin(), originalShapes.end(), KoShape::compareShapeZIndex);
0128         for (int i=0; i<originalShapes.size(); i++) {
0129             if (dynamic_cast<KoShapeGroup*>(originalShapes.at(i))) {
0130                 shapes << new GroupShape(dynamic_cast<KoShapeGroup*>(originalShapes.at(i)));
0131             } else {
0132                 shapes << new Shape(originalShapes.at(i));
0133             }
0134         }
0135 
0136     }
0137 
0138     return shapes;
0139 }