Krita

VectorLayer.cpp
1 /*
2  * SPDX-FileCopyrightText: 2017 Wolthera van Hövell tot Westerflier <[email protected]>
3  *
4  * SPDX-License-Identifier: LGPL-2.0-or-later
5  */
6 #include "VectorLayer.h"
7 #include <kis_shape_layer.h>
8 #include <kis_image.h>
9 #include <SvgWriter.h>
10 #include <SvgParser.h>
11 #include <QBuffer>
12 #include <commands/KoShapeCreateCommand.h>
13 #include <commands/KoShapeGroupCommand.h>
14 #include <KoShapeGroup.h>
15 #include <KisDocument.h>
16 #include <kis_processing_applicator.h>
17 #include <kis_group_layer.h>
18 
19 #include "Krita.h"
20 #include "GroupShape.h"
21 #include "LibKisUtils.h"
22 
23 
24 VectorLayer::VectorLayer(KoShapeControllerBase* shapeController, KisImageSP image, QString name, QObject *parent) :
25  Node(image, new KisShapeLayer(shapeController, image, name, OPACITY_OPAQUE_U8), parent)
26 {
27 
28 }
29 
30 VectorLayer::VectorLayer(KisShapeLayerSP layer, QObject *parent):
31  Node(layer->image(), layer, parent)
32 {
33 
34 }
35 
36 VectorLayer::~VectorLayer()
37 {
38 
39 }
40 
42 {
43  return "vectorlayer";
44 }
45 
47 {
49  KisShapeLayerSP vector = KisShapeLayerSP(dynamic_cast<KisShapeLayer*>(this->node().data()));
50  if (vector) {
51  QList<KoShape*> originalShapes = vector->shapes();
52  std::sort(originalShapes.begin(), originalShapes.end(), KoShape::compareShapeZIndex);
53  for (int i=0; i<vector->shapeCount(); i++) {
54  if (dynamic_cast<KoShapeGroup*>(originalShapes.at(i))) {
55  shapes << new GroupShape(dynamic_cast<KoShapeGroup*>(originalShapes.at(i)));
56  } else {
57  shapes << new Shape(originalShapes.at(i));
58  }
59  }
60  }
61  return shapes;
62 }
63 
65 {
66  QString svgData;
67  KisShapeLayerSP vector = KisShapeLayerSP(dynamic_cast<KisShapeLayer*>(this->node().data()));
68 
69  if (vector) {
70  QBuffer buffer;
71  QList<KoShape*> originalShapes = vector->shapes();
72 
73  std::sort(originalShapes.begin(), originalShapes.end(), KoShape::compareShapeZIndex);
74 
75  const QSizeF sizeInPx = this->node()->image()->bounds().size();
76  const QSizeF pageSize(sizeInPx.width() / this->node()->image()->xRes(),
77  sizeInPx.height() / this->node()->image()->yRes());
78 
79  buffer.open(QIODevice::WriteOnly);
80 
81  SvgWriter writer(originalShapes);
82 
83  writer.save(buffer, pageSize);
84  buffer.close();
85 
86  svgData = QString::fromUtf8(buffer.data());
87  }
88 
89  return svgData;
90 
91 }
92 
94 {
96  QList<KoShape*> originalShapes;
97 
98  if (svgData.isEmpty() || !svgData.contains("<svg") ) {
99  return shapes;
100  }
101 
102  KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(this->node().data());
103 
104  if (container) {
105  QSizeF fragmentSize;
106  QString errorMsg;
107  int errorLine = 0;
108  int errorColumn = 0;
109 
110  QDomDocument dom = SvgParser::createDocumentFromSvg(svgData, &errorMsg, &errorLine, &errorColumn);
111 
112  if (dom.isNull()) {
113  qWarning() << "Failed to process an SVG string at"
114  << errorLine << ":" << errorColumn << "->" << errorMsg;
115  return shapes;
116  }
117 
118  Document *document = Krita::instance()->activeDocument();
119 
120  if (!document) {
121  document = LibKisUtils::findNodeInDocuments(this->node());
122  if (!document) {
123  return shapes;
124  }
125  }
126 
127  SvgParser parser(document->document()->shapeController()->resourceManager());
128 
129  parser.setResolution(this->node()->image()->bounds(), this->node()->image()->xRes() * 72.0);
130 
131  originalShapes = parser.parseSvg(dom.documentElement(), &fragmentSize);
132 
133  KUndo2Command *cmd = new KoShapeCreateCommand(document->document()->shapeController(), originalShapes, container);
134 
135  KisProcessingApplicator::runSingleCommandStroke(this->node()->image(), cmd);
136  this->node()->image()->waitForDone();
137  delete document;
138 
139  std::sort(originalShapes.begin(), originalShapes.end(), KoShape::compareShapeZIndex);
140  for (int i=0; i<originalShapes.size(); i++) {
141  if (dynamic_cast<KoShapeGroup*>(originalShapes.at(i))) {
142  shapes << new GroupShape(dynamic_cast<KoShapeGroup*>(originalShapes.at(i)));
143  } else {
144  shapes << new Shape(originalShapes.at(i));
145  }
146  }
147 
148  }
149 
150  return shapes;
151 }
152 
154 {
155  KisShapeLayerSP vector = KisShapeLayerSP(dynamic_cast<KisShapeLayer*>(this->node().data()));
156 
157  if (!vector) return 0;
158 
159  KoShape* shape = vector->shapeManager()->shapeAt(position);
160 
161  if (!shape) return 0;
162 
163  if (dynamic_cast<KoShapeGroup*>(shape)) {
164  return new GroupShape(dynamic_cast<KoShapeGroup*>(shape));
165  } else {
166  return new Shape(shape);
167  }
168 
169 }
170 
171 QList<Shape *> VectorLayer::shapesInRect(const QRectF &rect, bool omitHiddenShapes, bool containedMode) const {
173  KisShapeLayerSP vector = KisShapeLayerSP(dynamic_cast<KisShapeLayer*>(this->node().data()));
174 
175  if (vector) {
176  QList<KoShape *> originalShapes = vector->shapeManager()->shapesAt(rect, omitHiddenShapes, containedMode);
177 
178  std::sort(originalShapes.begin(), originalShapes.end(), KoShape::compareShapeZIndex);
179  for (int i=0; i<originalShapes.size(); i++) {
180  if (dynamic_cast<KoShapeGroup*>(originalShapes.at(i))) {
181  shapes << new GroupShape(dynamic_cast<KoShapeGroup*>(originalShapes.at(i)));
182  } else {
183  shapes << new Shape(originalShapes.at(i));
184  }
185  }
186  }
187  return shapes;
188 }
189 
191 {
192  if (shapes.isEmpty()) return 0;
193 
194  QList<KoShape *> originalShapes;
195  KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(this->node().data());
196 
197  if (!container) return 0;
198 
199  for (Shape* shape : shapes) {
200  KoShape *originalShape = shape->shape();
201 
202  if (originalShape && originalShape->parent() == container) {
203  originalShapes << originalShape;
204  } else {
205  qWarning() << "Attempt to add an invalid shape.";
206  return 0;
207  }
208  }
209 
210  if (originalShapes.isEmpty()) return 0;
211 
212  Document *document = Krita::instance()->activeDocument();
213 
214  if (!document) {
215  document = LibKisUtils::findNodeInDocuments(this->node());
216  if (!document) return 0;
217  }
218 
219  KoShapeGroup *group = new KoShapeGroup();
220  const int groupZIndex = originalShapes.last()->zIndex();
221 
222  group->setZIndex(groupZIndex);
223  group->setName(name);
224 
225  KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Group shapes"));
226  new KoShapeCreateCommand(document->document()->shapeController(), group, container, cmd);
227  new KoShapeGroupCommand(group, originalShapes, true, cmd);
228 
229  KisProcessingApplicator::runSingleCommandStroke(this->node()->image(), cmd);
230  this->node()->image()->waitForDone();
231  delete document;
232 
233  return new GroupShape(group);
234 }
qreal height() const const
QList< Shape * > shapesInRect(const QRectF &rect, bool omitHiddenShapes=true, bool containedMode=false) const
shapeInRect get all non-group shapes that the shape's boundingBox() intersects or is contained within...
virtual bool open(QIODevice::OpenMode flags) override
QString fromUtf8(const char *str, int size)
const QByteArray & data() const const
bool isNull() const const
QString toSvg()
toSvg convert the shapes in the layer to svg.
Definition: VectorLayer.cpp:64
The Document class encapsulates a Krita Document/Image.
Definition: Document.h:33
The Shape class The shape class is a wrapper around Krita's vector objects.
Definition: Shape.h:37
QPoint position() const
position returns the position of the paint device of this node.
Definition: Node.cpp:621
int size() const const
QRect bounds() const
bounds return the exact bounds of the node's paint device
Definition: Node.cpp:608
static Krita * instance()
instance retrieve the singleton instance of the Application object.
Definition: Krita.cpp:402
bool isEmpty() const const
const T & at(int i) const const
bool isEmpty() const const
The GroupShape class A group shape is a vector object with child shapes.
Definition: GroupShape.h:20
QDomElement documentElement() const const
virtual void close() override
QList< Shape * > addShapesFromSvg(const QString &svg)
addShapesFromSvg add shapes to the layer from a valid svg.
Definition: VectorLayer.cpp:93
T & last()
Document * activeDocument() const
Definition: Krita.cpp:104
Node represents a layer or mask in a Krita image's Node hierarchy.
Definition: Node.h:21
QString name(StandardShortcut id)
QList::iterator begin()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QList::iterator end()
QString name() const
Definition: Node.cpp:421
Shape * createGroupShape(const QString &name, QList< Shape * > shapes) const
createGroupShape combine a list of top level shapes into a group.
virtual QString type() const override
type Krita has several types of nodes, split in layers and masks.
Definition: VectorLayer.cpp:41
Shape * shapeAtPosition(const QPointF &position) const
shapeAtPoint check if the position is located within any non-group shape's boundingBox() on the curre...
QList< Shape * > shapes() const
shapes
Definition: VectorLayer.cpp:46
qreal width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 04:08:41 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.