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 file.open(QIODevice::ReadOnly);
240 d->data = file.readAll();
241 file.close();
242 }
243
244 QBuffer buf(&d->data);
245 buf.open(QBuffer::ReadOnly);
246
247 QScopedPointer<KoStore> store(KoStore::createStore(&buf, KoStore::Read, "application/x-krita-gamutmask", KoStore::Zip));
248 if (!store || store->bad()) return false;
249
250 bool storeOpened = store->open("gamutmask.svg");
251 if (!storeOpened) { return false; }
252
253 QByteArray data;
254 data.resize(store->size());
255 QByteArray ba = store->read(store->size());
256 store->close();
257
258 if (ba.size() == 0) { // empty gamutmask.svg is possible when the first temporary resource is saved
260 d->maskSize = QSizeF(0, 0);
261 d->title = "";
262 } else {
263
264 QString errorMsg;
265 int errorLine = 0;
266 int errorColumn = 0;
267
268 QDomDocument xmlDocument = SvgParser::createDocumentFromSvg(ba, &errorMsg, &errorLine, &errorColumn);
269 if (xmlDocument.isNull()) {
270
271 errorFlake << "Parsing error in " << filename() << "! Aborting!" << Qt::endl
272 << " In line: " << errorLine << ", column: " << errorColumn << Qt::endl
273 << " Error message: " << errorMsg << Qt::endl;
274 errorFlake << "Parsing error in the main document at line" << errorLine
275 << ", column" << errorColumn << Qt::endl
276 << "Error message: " << errorMsg;
277
278 return false;
279 }
280
282 SvgParser parser(&manager);
283 parser.setResolution(QRectF(0,0,100,100), 72); // initialize with default values
284 QSizeF fragmentSize;
285
286 QList<KoShape*> shapes = parser.parseSvg(xmlDocument.documentElement(), &fragmentSize);
287
288 d->maskSize = fragmentSize;
289
290 d->title = parser.documentTitle();
291 setName(d->title);
293
294 setMaskShapes(shapes);
295
296 }
297
298
299
300 if (store->open("preview.png")) {
301 KoStoreDevice previewDev(store.data());
302 previewDev.open(QIODevice::ReadOnly);
303
304 QImage preview = QImage();
305 preview.load(&previewDev, "PNG");
306 setImage(preview);
307
308 (void)store->close();
309 }
310
311 buf.close();
312
313 setValid(true);
314
315 return true;
316}
317
322
324{
325 QList<KoShape*> shapes;
326 for(KoGamutMaskShape* maskShape: d->maskShapes) {
327 shapes.append(maskShape->koShape());
328 }
329
330 return shapes;
331}
332
333bool KoGamutMask::saveToDevice(QIODevice *dev) const
334{
335 KoStore* store(KoStore::createStore(dev, KoStore::Write, "application/x-krita-gamutmask", KoStore::Zip));
336 if (!store || store->bad()) return false;
337
338 QList<KoShape*> shapes = koShapes();
339
340 std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
341
342 if (!store->open("gamutmask.svg")) {
343 return false;
344 }
345
346 KoStoreDevice storeDev(store);
347 storeDev.open(QIODevice::WriteOnly);
348
349 SvgWriter writer(shapes);
350 writer.setDocumentTitle(d->title);
352
353 writer.save(storeDev, d->maskSize);
354
355 if (!store->close()) { return false; }
356
357
358 if (!store->open("preview.png")) {
359 return false;
360 }
361
362 KoStoreDevice previewDev(store);
363 previewDev.open(QIODevice::WriteOnly);
364
365 image().save(&previewDev, "PNG");
366 if (!store->close()) { return false; }
367
368 return store->finalize();
369}
370
371QString KoGamutMask::title() const
372{
373 return d->title;
374}
375
376void KoGamutMask::setTitle(QString title)
377{
378 d->title = title;
379 setName(title);
380}
381
383{
384 QMap<QString, QVariant> m = metadata();
385 return m["description"].toString();
386}
387
388void KoGamutMask::setDescription(QString description)
389{
390 addMetaData("description", description);
391}
392
394{
395 return ".kgm";
396}
397
399{
400 return d->rotation;
401}
402
403void KoGamutMask::setRotation(int rotation)
404{
406}
407
409{
410 return d->maskSize;
411}
412
417
419{
420 targetVector.clear();
421
422 for(KoShape* sh: shapes) {
423 KoGamutMaskShape* maskShape = new KoGamutMaskShape(sh);
424 targetVector.append(maskShape);
425 }
426}
427
428// clean up when ending mask preview
430{
431 d->previewShapes.clear();
432}
#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:223
static bool compareShapeZIndex(KoShape *s1, KoShape *s2)
Definition KoShape.cpp:434
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
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:308
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