Krita

VectorLayer.cpp
1/*
2 * SPDX-FileCopyrightText: 2017 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
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
24VectorLayer::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
30VectorLayer::VectorLayer(KisShapeLayerSP layer, QObject *parent):
31 Node(layer->image(), layer, parent)
32{
33
34}
35
36VectorLayer::~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))) {
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
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))) {
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
171QList<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))) {
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}
235
236
238{
239 KisShapeLayerSP vectorLayer = KisShapeLayerSP(dynamic_cast<KisShapeLayer*>(this->node().data()));
240 return vectorLayer->antialiased();
241}
242
243void VectorLayer::setAntialiased(const bool antialiased)
244{
245 KisShapeLayerSP vectorLayer = KisShapeLayerSP(dynamic_cast<KisShapeLayer*>(this->node().data()));
246 vectorLayer->setAntialiased(antialiased);
247}
The Document class encapsulates a Krita Document/Image.
Definition Document.h:37
The GroupShape class A group shape is a vector object with child shapes.
Definition GroupShape.h:21
Document * activeDocument() const
Definition Krita.cpp:104
static Krita * instance()
instance retrieve the singleton instance of the Application object.
Definition Krita.cpp:402
Node represents a layer or mask in a Krita image's Node hierarchy.
Definition Node.h:24
QPoint position() const
position returns the position of the paint device of this node.
Definition Node.cpp:627
QString name() const
Definition Node.cpp:427
QRect bounds() const
bounds return the exact bounds of the node's paint device
Definition Node.cpp:614
The Shape class The shape class is a wrapper around Krita's vector objects.
Definition Shape.h:38
bool isAntialiased() const
return antialiasing status for the Vector layer
virtual QString type() const override
type Krita has several types of nodes, split in layers and masks.
QList< Shape * > addShapesFromSvg(const QString &svg)
addShapesFromSvg add shapes to the layer from a valid svg.
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...
QList< Shape * > shapes() const
shapes
QString toSvg()
toSvg convert the shapes in the layer to svg.
Shape * createGroupShape(const QString &name, QList< Shape * > shapes) const
createGroupShape combine a list of top level shapes into a group.
void setAntialiased(const bool antialiased)
set antialiasing status for the Vector layer
Shape * shapeAtPosition(const QPointF &position) const
shapeAtPoint check if the position is located within any non-group shape's boundingBox() on the curre...
QString name(StandardAction id)
virtual void close() override
const QByteArray & data() const const
virtual bool open(OpenMode flags) override
QDomElement documentElement() const const
bool isNull() const const
const_reference at(qsizetype i) const const
iterator begin()
iterator end()
bool isEmpty() const const
T & last()
qsizetype size() const const
qreal height() const const
qreal width() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:18:59 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.