Krita Source Code Documentation
Loading...
Searching...
No Matches
KoGamutMask.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2018 Anna Medonosova <anna.medonosova@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "KoGamutMask.h"
8
9#include <cstring>
10
11#include <QVector>
12#include <QString>
13#include <QFile>
14#include <QList>
15#include <QDomDocument>
16#include <QDomElement>
17#include <QByteArray>
18#include <QBuffer>
19#include <QScopedPointer>
20
21#include <FlakeDebug.h>
22
23#include <KoStore.h>
24#include <KoStoreDevice.h>
26#include <SvgParser.h>
27#include <SvgWriter.h>
28#include <KoShape.h>
29#include <kis_assert.h>
30#include <QTransform>
31#include <KoMarker.h>
32
33//#include <kis_debug.h>
34
36 : m_maskShape(shape)
37{
38}
39
43
48
53
54bool KoGamutMaskShape::coordIsClear(const QPointF& coord) const
55{
56 bool isClear = m_maskShape->hitTest(coord);
57
58 return isClear;
59}
60
61void KoGamutMaskShape::paint(QPainter &painter)
62{
63 painter.save();
64 painter.setTransform(m_maskShape->absoluteTransformation(), true);
65 m_maskShape->paint(painter);
66 painter.restore();
67}
68
69void KoGamutMaskShape::paintStroke(QPainter &painter)
70{
71 painter.save();
72 painter.setTransform(m_maskShape->absoluteTransformation(), true);
73 m_maskShape->paintStroke(painter);
74 painter.restore();
75}
76
86
87KoGamutMask::KoGamutMask(const QString& filename)
88 : KoResource(filename)
89 , d(new Private)
90{
91 d->maskSize = QSizeF(144.0,144.0);
92 setRotation(0);
93}
94
96 : KoResource(QString())
97 , d(new Private)
98{
99 d->maskSize = QSizeF(144.0,144.0);
100 setRotation(0);
101}
102
107
109 : QObject(0)
110 , KoResource(rhs)
111 , d(new Private)
112{
113 setTitle(rhs.title());
115 d->maskSize = rhs.d->maskSize;
116
117 QList<KoShape*> newShapes;
118 for(KoShape* sh: rhs.koShapes()) {
119 newShapes.append(sh->cloneShape());
120 }
121 setMaskShapes(newShapes);
122}
123
125{
126 return KoResourceSP(new KoGamutMask(*this));
127}
128
130{
131 qDeleteAll(d->maskShapes);
132 qDeleteAll(d->previewShapes);
133 delete d;
134}
135
136bool KoGamutMask::coordIsClear(const QPointF& coord, bool preview)
137{
138 QVector<KoGamutMaskShape*>* shapeVector;
139
140 if (preview && !d->previewShapes.isEmpty()) {
141 shapeVector = &d->previewShapes;
142 } else {
143 shapeVector = &d->maskShapes;
144 }
145
146 for(KoGamutMaskShape* shape: *shapeVector) {
147 if (shape->coordIsClear(coord) == true) {
148 return true;
149 }
150 }
151
152 return false;
153}
154
155void KoGamutMask::paint(QPainter &painter, bool preview)
156{
157 QVector<KoGamutMaskShape*>* shapeVector;
158
159 if (preview && !d->previewShapes.isEmpty()) {
160 shapeVector = &d->previewShapes;
161 } else {
162 shapeVector = &d->maskShapes;
163 }
164
165 for(KoGamutMaskShape* shape: *shapeVector) {
166 shape->paint(painter);
167 }
168}
169
170void KoGamutMask::paintStroke(QPainter &painter, bool preview)
171{
172 QVector<KoGamutMaskShape*>* shapeVector;
173
174 if (preview && !d->previewShapes.isEmpty()) {
175 shapeVector = &d->previewShapes;
176 } else {
177 shapeVector = &d->maskShapes;
178 }
179
180 for(KoGamutMaskShape* shape: *shapeVector) {
181 shape->paintStroke(painter);
182 }
183}
184
185QTransform KoGamutMask::maskToViewTransform(qreal viewSize)
186{
187 // apply mask rotation before drawing
188 QPointF centerPoint(viewSize*0.5, viewSize*0.5);
189
190 QTransform transform;
191 transform.translate(centerPoint.x(), centerPoint.y());
192 transform.rotate(rotation());
193 transform.translate(-centerPoint.x(), -centerPoint.y());
194
195 qreal scale = viewSize/(maskSize().width());
196 transform.scale(scale, scale);
197
198 return transform;
199}
200
201QTransform KoGamutMask::viewToMaskTransform(qreal viewSize)
202{
203 QPointF centerPoint(viewSize*0.5, viewSize*0.5);
204
205 QTransform transform;
206 qreal scale = viewSize/(maskSize().width());
207 transform.scale(1/scale, 1/scale);
208
209 transform.translate(centerPoint.x(), centerPoint.y());
210 transform.rotate(-rotation());
211 transform.translate(-centerPoint.x(), -centerPoint.y());
212
213 return transform;
214}
215
216bool KoGamutMask::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface)
217{
218 Q_UNUSED(resourcesInterface);
219
220 if (!dev->isOpen()) dev->open(QIODevice::ReadOnly);
221
222 d->data = dev->readAll();
223
224 // TODO: test
225 KIS_ASSERT_RECOVER_RETURN_VALUE(d->data.size() != 0, false);
226
227 if (filename().isNull()) {
228 warnFlake << "Cannot load gamut mask" << name() << "there is no filename set";
229 return false;
230 }
231
232 if (d->data.isNull()) {
233 QFile file(filename());
234 if (file.size() == 0) {
235 warnFlake << "Cannot load gamut mask" << name() << "there is no data available";
236 return false;
237 }
238
239 if (!file.open(QIODevice::ReadOnly)) {
240 warnFlake << "Cannot load gamut mask" << name() << ":" << file.errorString();
241 return false;
242 }
243 d->data = file.readAll();
244 file.close();
245 }
246
247 QBuffer buf(&d->data);
248 buf.open(QBuffer::ReadOnly);
249
250 QScopedPointer<KoStore> store(KoStore::createStore(&buf, KoStore::Read, "application/x-krita-gamutmask", KoStore::Zip));
251 if (!store || store->bad()) return false;
252
253 bool storeOpened = store->open("gamutmask.svg");
254 if (!storeOpened) { return false; }
255
256 QByteArray data;
257 data.resize(store->size());
258 QByteArray ba = store->read(store->size());
259 store->close();
260
261 if (ba.size() == 0) { // empty gamutmask.svg is possible when the first temporary resource is saved
263 d->maskSize = QSizeF(0, 0);
264 d->title = "";
265 } else {
266
267 QString errorMsg;
268 int errorLine = 0;
269 int errorColumn = 0;
270
271 QDomDocument xmlDocument = SvgParser::createDocumentFromSvg(ba, &errorMsg, &errorLine, &errorColumn);
272 if (xmlDocument.isNull()) {
273
274 errorFlake << "Parsing error in " << filename() << "! Aborting!" << Qt::endl
275 << " In line: " << errorLine << ", column: " << errorColumn << Qt::endl
276 << " Error message: " << errorMsg << Qt::endl;
277 errorFlake << "Parsing error in the main document at line" << errorLine
278 << ", column" << errorColumn << Qt::endl
279 << "Error message: " << errorMsg;
280
281 return false;
282 }
283
285 SvgParser parser(&manager);
286 parser.setResolution(QRectF(0,0,100,100), 72); // initialize with default values
287 QSizeF fragmentSize;
288
289 QList<KoShape*> shapes = parser.parseSvg(xmlDocument.documentElement(), &fragmentSize);
290
291 d->maskSize = fragmentSize;
292
293 d->title = parser.documentTitle();
294 setName(d->title);
296
297 setMaskShapes(shapes);
298
299 }
300
301
302
303 if (store->open("preview.png")) {
304 KoStoreDevice previewDev(store.data());
305 previewDev.open(QIODevice::ReadOnly);
306
307 QImage preview = QImage();
308 preview.load(&previewDev, "PNG");
309 setImage(preview);
310
311 (void)store->close();
312 }
313
314 buf.close();
315
316 setValid(true);
317
318 return true;
319}
320
325
327{
328 QList<KoShape*> shapes;
329 for(KoGamutMaskShape* maskShape: d->maskShapes) {
330 shapes.append(maskShape->koShape());
331 }
332
333 return shapes;
334}
335
336bool KoGamutMask::saveToDevice(QIODevice *dev) const
337{
338 KoStore* store(KoStore::createStore(dev, KoStore::Write, "application/x-krita-gamutmask", KoStore::Zip));
339 if (!store || store->bad()) return false;
340
341 QList<KoShape*> shapes = koShapes();
342
343 std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
344
345 if (!store->open("gamutmask.svg")) {
346 return false;
347 }
348
349 KoStoreDevice storeDev(store);
350 storeDev.open(QIODevice::WriteOnly);
351
352 SvgWriter writer(shapes);
353 writer.setDocumentTitle(d->title);
355
356 writer.save(storeDev, d->maskSize);
357
358 if (!store->close()) { return false; }
359
360
361 if (!store->open("preview.png")) {
362 return false;
363 }
364
365 KoStoreDevice previewDev(store);
366 previewDev.open(QIODevice::WriteOnly);
367
368 image().save(&previewDev, "PNG");
369 if (!store->close()) { return false; }
370
371 return store->finalize();
372}
373
374QString KoGamutMask::title() const
375{
376 return d->title;
377}
378
379void KoGamutMask::setTitle(QString title)
380{
381 d->title = title;
382 setName(title);
383}
384
386{
387 QMap<QString, QVariant> m = metadata();
388 return m["description"].toString();
389}
390
391void KoGamutMask::setDescription(QString description)
392{
393 addMetaData("description", description);
394}
395
397{
398 return ".kgm";
399}
400
402{
403 return d->rotation;
404}
405
406void KoGamutMask::setRotation(int rotation)
407{
409}
410
412{
413 return d->maskSize;
414}
415
420
422{
423 targetVector.clear();
424
425 for(KoShape* sh: shapes) {
426 KoGamutMaskShape* maskShape = new KoGamutMaskShape(sh);
427 targetVector.append(maskShape);
428 }
429}
430
431// clean up when ending mask preview
433{
434 d->previewShapes.clear();
435}
#define warnFlake
Definition FlakeDebug.h:16
#define errorFlake
Definition FlakeDebug.h:17
bool coordIsClear(const QPointF &coord) const
void paintStroke(QPainter &painter)
void paint(QPainter &painter)
KoShape * m_maskShape
Definition KoGamutMask.h:36
KoShape * koShape()
The resource type for gamut masks used by the artistic color selector.
Definition KoGamutMask.h:44
void paint(QPainter &painter, bool preview)
QTransform viewToMaskTransform(qreal viewSize)
QSizeF maskSize()
QString title() const
void setPreviewMaskShapes(QList< KoShape * > shapes)
bool loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface) override
~KoGamutMask() override
QTransform maskToViewTransform(qreal viewSize)
void clearPreview()
void setMaskShapes(QList< KoShape * > shapes)
KoResourceSP clone() const override
QString defaultFileExtension() const override
void setRotation(int rotation)
void paintStroke(QPainter &painter, bool preview)
void setMaskShapesToVector(QList< KoShape * > shapes, QVector< KoGamutMaskShape * > &targetVector)
void setDescription(QString description)
bool coordIsClear(const QPointF &coord, bool preview)
void setTitle(QString title)
QString description() const
bool saveToDevice(QIODevice *dev) const override
Private *const d
Definition KoGamutMask.h:95
QList< KoShape * > koShapes() const
virtual void paintStroke(QPainter &painter) const
paintStroke paints the shape's stroked outline
Definition KoShape.cpp:196
static bool compareShapeZIndex(KoShape *s1, KoShape *s2)
Definition KoShape.cpp:388
QTransform absoluteTransformation() const
Definition KoShape.cpp:330
virtual void paint(QPainter &painter) const =0
Paint the shape fill The class extending this one is responsible for painting itself....
virtual bool hitTest(const QPointF &position) const
Check if the shape is hit on position.
Definition KoShape.cpp:281
bool open(OpenMode m) override
bool close()
Definition KoStore.cpp:156
@ Read
Definition KoStore.h:29
@ Write
Definition KoStore.h:29
@ Zip
Definition KoStore.h:30
bool bad() const
Definition KoStore.cpp:414
static KoStore * createStore(const QString &fileName, Mode mode, const QByteArray &appIdentification=QByteArray(), Backend backend=Auto, bool writeMimetype=true)
Definition KoStore.cpp:39
bool finalize()
Definition KoStore.cpp:395
bool open(const QString &name)
Definition KoStore.cpp:109
static QDomDocument createDocumentFromSvg(QIODevice *device, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0)
QString documentTitle() const
QList< KoShape * > parseSvg(const QDomElement &e, QSizeF *fragmentSize=0)
Parses a svg fragment, returning the list of top level child shapes.
void setResolution(const QRectF boundsInPixels, qreal pixelsPerInch)
QString documentDescription() const
Implements exporting shapes to SVG.
Definition SvgWriter.h:33
void setDocumentDescription(QString description)
bool save(QIODevice &outputDevice, const QSizeF &pageSize)
Writes svg to specified output device.
Definition SvgWriter.cpp:82
void setDocumentTitle(QString title)
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:85
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
QSharedPointer< KoResource > KoResourceSP
QVector< KoGamutMaskShape * > maskShapes
QVector< KoGamutMaskShape * > previewShapes
void setValid(bool valid)
void setName(const QString &name)
void addMetaData(QString key, QVariant value)
store the given key, value pair in the resource
QImage image
QString filename
void setImage(const QImage &image)
QMap< QString, QVariant > metadata
QString name