Krita Source Code Documentation
Loading...
Searching...
No Matches
KoStopGradient.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2005 Tim Beaulen <tbscope@gmail.org>
3 SPDX-FileCopyrightText: 2007 Jan Hambrecht <jaham@gmx.net>
4 SPDX-FileCopyrightText: 2007 Sven Langkamp <sven.langkamp@gmail.com>
5 SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
6
7 SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
11
12#include <array>
13#include <cfloat>
14#include <cmath>
15
16#include <QColor>
17#include <QFile>
18#include <QDomDocument>
19#include <QDomElement>
20#include <QBuffer>
21
22#include <klocalizedstring.h>
23#include <DebugPigment.h>
24
26#include <KoColorSpaceEngine.h>
27#include <KoColorProfile.h>
28#include "KoMixColorsOp.h"
29
30#include "kis_dom_utils.h"
31
33#include <KoXmlNS.h>
34
37
38
39KoStopGradient::KoStopGradient(const QString& filename)
40 : KoAbstractGradient(filename)
41{
42}
43
47
50 , m_stops(rhs.m_stops)
51 , m_start(rhs.m_start)
52 , m_stop(rhs.m_stop)
53 , m_focalPoint(rhs.m_focalPoint)
54{
55}
56
58{
59 return
60 *colorSpace() == *rhs.colorSpace() &&
61 spread() == rhs.spread() &&
62 type() == rhs.type() &&
63 m_start == rhs.m_start &&
64 m_stop == rhs.m_stop &&
66 m_stops == rhs.m_stops;
67}
68
70{
71 return KoResourceSP(new KoStopGradient(*this));
72}
73
74bool KoStopGradient::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface)
75{
76 Q_UNUSED(resourcesInterface);
77 loadSvgGradient(dev);
78 if (m_stops.count() >= 2) {
79 setValid(true);
80 }
82 return true;
83}
84
86{
87 QGradient* gradient;
88
89 switch (type()) {
90 case QGradient::LinearGradient: {
91 gradient = new QLinearGradient(m_start, m_stop);
92 break;
93 }
94 case QGradient::RadialGradient: {
95 QPointF diff = m_stop - m_start;
96 qreal radius = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
97 gradient = new QRadialGradient(m_start, radius, m_focalPoint);
98 break;
99 }
100 case QGradient::ConicalGradient: {
101 qreal angle = atan2(m_start.y(), m_start.x()) * 180.0 / M_PI;
102 if (angle < 0.0)
103 angle += 360.0;
104 gradient = new QConicalGradient(m_start, angle);
105 break;
106 }
107 default:
108 return 0;
109 }
110 QColor color;
111 for (QList<KoGradientStop>::const_iterator i = m_stops.begin(); i != m_stops.end(); ++i) {
112 i->color.toQColor(&color);
113 gradient->setColorAt(i->position, color);
114 }
115
116 gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
117 gradient->setSpread(this->spread());
118
119 return gradient;
120}
121
122bool KoStopGradient::stopsAt(KoGradientStop& leftStop, KoGradientStop& rightStop, qreal t) const
123{
124 if (!m_stops.count())
125 return false;
126
127 KIS_SAFE_ASSERT_RECOVER(!qIsNaN(t)) { // if it's nan, it would crash in the last 'else'
128 leftStop = m_stops.first();
129 rightStop = KoGradientStop(-std::numeric_limits<double>::infinity(), leftStop.color, leftStop.type);
130 return true;
131 }
132
133 if (t <= m_stops.first().position || m_stops.count() == 1) {
134 // we have only one stop or t is before the first stop
135 leftStop = m_stops.first();
136 rightStop = KoGradientStop(-std::numeric_limits<double>::infinity(), leftStop.color, leftStop.type);
137 return true;
138 } else if (t >= m_stops.last().position) {
139 // t is after the last stop
140 rightStop = m_stops.last();
141 leftStop = KoGradientStop(std::numeric_limits<double>::infinity(), rightStop.color, rightStop.type);
142 return true;
143 } else {
144 // we have at least two color stops
145 // -> find the two stops which frame our t
146 auto it = std::lower_bound(m_stops.begin(), m_stops.end(), KoGradientStop(t, KoColor(), COLORSTOP),
148 leftStop = *(it - 1);
149 rightStop = *(it);
150 return true;
151 }
152}
153
154void KoStopGradient::colorAt(KoColor& dst, qreal t) const
155{
156 KoGradientStop leftStop, rightStop;
157 if (!stopsAt(leftStop, rightStop, t)) return;
158
159 const KoColorSpace *mixSpace = dst.colorSpace();
160
161 KoColor buffer(mixSpace);
162 KoColor startDummy(leftStop.color, mixSpace);
163 KoColor endDummy(rightStop.color, mixSpace);
164
165 const std::array<quint8 *, 2> colors = {{startDummy.data(), endDummy.data()}};
166
167 qreal localT = NAN;
168 qreal stopDistance = rightStop.position - leftStop.position;
169 if (stopDistance < DBL_EPSILON) {
170 localT = 0.5;
171 } else {
172 localT = (t - leftStop.position) / stopDistance;
173 }
174 std::array<qint16, 2> colorWeights {};
175 colorWeights[0] = std::lround((1.0 - localT) * qint16_MAX);
176 colorWeights[1] = qint16_MAX - colorWeights[0];
177
178 mixSpace->mixColorsOp()->mixColors(colors.data(), colorWeights.data(), 2, buffer.data(), qint16_MAX);
179
180 dst = buffer;
181}
182
184{
185 if (!gradient)
187
188 QSharedPointer<KoStopGradient> newGradient(new KoStopGradient(QString()));
189 newGradient->setType(gradient->type());
190 newGradient->setSpread(gradient->spread());
191
192 switch (gradient->type()) {
193 case QGradient::LinearGradient: {
194 const QLinearGradient* g = static_cast<const QLinearGradient*>(gradient);
195 newGradient->m_start = g->start();
196 newGradient->m_stop = g->finalStop();
197 newGradient->m_focalPoint = g->start();
198 break;
199 }
200 case QGradient::RadialGradient: {
201 const QRadialGradient* g = static_cast<const QRadialGradient*>(gradient);
202 newGradient->m_start = g->center();
203 newGradient->m_stop = g->center() + QPointF(g->radius(), 0);
204 newGradient->m_focalPoint = g->focalPoint();
205 break;
206 }
207 case QGradient::ConicalGradient: {
208 const QConicalGradient* g = static_cast<const QConicalGradient*>(gradient);
209 qreal radian = g->angle() * M_PI / 180.0;
210 newGradient->m_start = g->center();
211 newGradient->m_stop = QPointF(100.0 * cos(radian), 100.0 * sin(radian));
212 newGradient->m_focalPoint = g->center();
213 break;
214 }
215 default:
217 }
218
219 Q_FOREACH(const QGradientStop & stop, gradient->stops()) {
220 KoColor color(newGradient->colorSpace());
221 color.fromQColor(stop.second);
222 newGradient->m_stops.append(KoGradientStop(stop.first, color, COLORSTOP));
223 }
224
225 newGradient->setValid(true);
226
227 return newGradient;
228}
229
231{
232 m_stops.clear();
233 m_hasVariableStops = false;
234 KoColor color;
235 Q_FOREACH(const KoGradientStop & stop, stops) {
236 color = stop.color;
237 m_stops.append(KoGradientStop(stop.position, color, stop.type));
238 if (stop.type != COLORSTOP) {
239 m_hasVariableStops = true;
240 }
241 }
242 if (m_stops.count() >= 2) {
243 setValid(true);
244 } else {
245 setValid(false);
246 }
248}
249
254
256{
257 QList<int> result;
258
259 if (std::find_if_not(m_stops.begin(), m_stops.end(),
261 != m_stops.end()) {
262
264 }
265
266 return result;
267}
268
270{
271 const KoColor fgColor = canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>();
272 const KoColor bgColor = canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>();
273
274 for (auto it = m_stops.begin(); it != m_stops.end(); ++it) {
275 if (it->type == FOREGROUNDSTOP) {
276 it->color = fgColor;
277 it->type = COLORSTOP;
278 } else if (it->type == BACKGROUNDSTOP) {
279 it->color = bgColor;
280 it->type = COLORSTOP;
281 }
282 }
283}
284
286{
287 const KoColor fgColor = canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>();
288 const KoColor bgColor = canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>();
289
290 for (auto it = m_stops.begin(); it != m_stops.end(); ++it) {
291 if (it->type == FOREGROUNDSTOP) {
292 it->color = fgColor;
293 } else if (it->type == BACKGROUNDSTOP) {
294 it->color = bgColor;
295 }
296 }
297}
298
300{
301 QDomDocument doc;
302
303 if (!(doc.setContent(file))) {
304 file->close();
305 } else {
306 QHash<QString, const KoColorProfile*> profiles;
307 for (QDomElement e = doc.documentElement().firstChildElement("defs"); !e.isNull(); e = e.nextSiblingElement("defs")) {
308 for (QDomElement profileEl = e.firstChildElement("color-profile"); !profileEl.isNull(); profileEl = profileEl.nextSiblingElement("color-profile")) {
309 const QString href = profileEl.attribute("xlink:href");
310 const QByteArray uniqueId = QByteArray::fromHex(profileEl.attribute("local").toLatin1());
311 const QString name = profileEl.attribute("name");
312
313 const KoColorProfile *profile =
315 if (!profile) {
316 QFile file(href);
317 if (file.size() > 0 && file.open(QIODevice::ReadOnly)) {
319 KIS_ASSERT(engine);
320 profile = engine->addProfile(href);
321 }
322 }
323
324
325 if (profile && !profiles.contains(name)) {
326 profiles.insert(name, profile);
327 }
328 }
329 }
330 for (QDomNode n = doc.documentElement().firstChild(); !n.isNull(); n = n.nextSibling()) {
331 QDomElement e = n.toElement();
332
333 if (e.isNull()) continue;
334
335 if (e.tagName() == "linearGradient" || e.tagName() == "radialGradient") {
336 parseSvgGradient(e, profiles);
337 return;
338 }
339 // Inkscape gradients are in another defs
340 if (e.tagName() == "defs") {
341
342
343 for (QDomNode defnode = e.firstChild(); !defnode.isNull(); defnode = defnode.nextSibling()) {
344 QDomElement defelement = defnode.toElement();
345
346 if (defelement.isNull()) continue;
347
348 if (defelement.tagName() == "linearGradient" || defelement.tagName() == "radialGradient") {
349 parseSvgGradient(defelement, profiles);
350 return;
351 }
352 }
353 }
354 }
355 }
356}
357
358
359void KoStopGradient::parseSvgGradient(const QDomElement& element, QHash<QString, const KoColorProfile *> profiles)
360{
361 m_stops.clear();
362 m_hasVariableStops = false;
363 setSpread(QGradient::PadSpread);
364
365 /*QString href = e.attribute( "xlink:href" ).mid( 1 );
366 if( !href.isEmpty() )
367 {
368 }*/
369 setName(element.attribute("id", i18n("SVG Gradient")));
370
371 bool bbox = element.attribute("gradientUnits") != "userSpaceOnUse";
372
373 if (element.tagName() == "linearGradient") {
374
375 if (bbox) {
376 QString s;
377
378 s = element.attribute("x1", "0%");
379 qreal xOrigin;
380 if (s.endsWith('%'))
381 xOrigin = s.remove('%').toDouble();
382 else
383 xOrigin = s.toDouble() * 100.0;
384
385 s = element.attribute("y1", "0%");
386 qreal yOrigin;
387 if (s.endsWith('%'))
388 yOrigin = s.remove('%').toDouble();
389 else
390 yOrigin = s.toDouble() * 100.0;
391
392 s = element.attribute("x2", "100%");
393 qreal xVector;
394 if (s.endsWith('%'))
395 xVector = s.remove('%').toDouble();
396 else
397 xVector = s.toDouble() * 100.0;
398
399 s = element.attribute("y2", "0%");
400 qreal yVector;
401 if (s.endsWith('%'))
402 yVector = s.remove('%').toDouble();
403 else
404 yVector = s.toDouble() * 100.0;
405
406 m_start = QPointF(xOrigin, yOrigin);
407 m_stop = QPointF(xVector, yVector);
408 }
409 else {
410 m_start = QPointF(element.attribute("x1").toDouble(), element.attribute("y1").toDouble());
411 m_stop = QPointF(element.attribute("x2").toDouble(), element.attribute("y2").toDouble());
412 }
413 setType(QGradient::LinearGradient);
414 }
415 else {
416 if (bbox) {
417 QString s;
418
419 s = element.attribute("cx", "50%");
420 qreal xOrigin;
421 if (s.endsWith('%'))
422 xOrigin = s.remove('%').toDouble();
423 else
424 xOrigin = s.toDouble() * 100.0;
425
426 s = element.attribute("cy", "50%");
427 qreal yOrigin;
428 if (s.endsWith('%'))
429 yOrigin = s.remove('%').toDouble();
430 else
431 yOrigin = s.toDouble() * 100.0;
432
433 s = element.attribute("cx", "50%");
434 qreal xVector;
435 if (s.endsWith('%'))
436 xVector = s.remove('%').toDouble();
437 else
438 xVector = s.toDouble() * 100.0;
439
440 s = element.attribute("r", "50%");
441 if (s.endsWith('%'))
442 xVector += s.remove('%').toDouble();
443 else
444 xVector += s.toDouble() * 100.0;
445
446 s = element.attribute("cy", "50%");
447 qreal yVector;
448 if (s.endsWith('%'))
449 yVector = s.remove('%').toDouble();
450 else
451 yVector = s.toDouble() * 100.0;
452
453 s = element.attribute("fx", "50%");
454 qreal xFocal;
455 if (s.endsWith('%'))
456 xFocal = s.remove('%').toDouble();
457 else
458 xFocal = s.toDouble() * 100.0;
459
460 s = element.attribute("fy", "50%");
461 qreal yFocal;
462 if (s.endsWith('%'))
463 yFocal = s.remove('%').toDouble();
464 else
465 yFocal = s.toDouble() * 100.0;
466
467 m_start = QPointF(xOrigin, yOrigin);
468 m_stop = QPointF(xVector, yVector);
469 m_focalPoint = QPointF(xFocal, yFocal);
470 }
471 else {
472 m_start = QPointF(element.attribute("cx").toDouble(), element.attribute("cy").toDouble());
473 m_stop = QPointF(element.attribute("cx").toDouble() + element.attribute("r").toDouble(),
474 element.attribute("cy").toDouble());
475 m_focalPoint = QPointF(element.attribute("fx").toDouble(), element.attribute("fy").toDouble());
476 }
477 setType(QGradient::RadialGradient);
478 }
479 // handle spread method
480 QString spreadMethod = element.attribute("spreadMethod");
481 if (!spreadMethod.isEmpty()) {
482 if (spreadMethod == "reflect")
483 setSpread(QGradient::ReflectSpread);
484 else if (spreadMethod == "repeat")
485 setSpread(QGradient::RepeatSpread);
486 }
487
488 for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) {
489 QDomElement colorstop = n.toElement();
490 if (colorstop.tagName() == "stop") {
491 qreal opacity = 0.0;
492 KoColor color;
493 float off;
494 QString temp = colorstop.attribute("offset");
495 if (temp.contains('%')) {
496 temp = temp.left(temp.length() - 1);
497 off = temp.toFloat() / 100.0;
498 }
499 else
500 off = temp.toFloat();
501
502 if (!colorstop.attribute("stop-color").isEmpty())
503 color = KoColor::fromSVG11(colorstop.attribute("stop-color"), profiles);
504 else {
505 // try style attr
506 QString style = colorstop.attribute("style").simplified();
507 QStringList substyles = style.split(';', Qt::SkipEmptyParts);
508 Q_FOREACH(const QString & s, substyles) {
509 QStringList substyle = s.split(':');
510 QString command = substyle[0].trimmed();
511 QString params = substyle[1].trimmed();
512 if (command == "stop-color")
513 color = KoColor::fromSVG11(params, profiles);
514 if (command == "stop-opacity")
515 opacity = params.toDouble();
516 }
517
518 }
519 if (!colorstop.attribute("stop-opacity").isEmpty())
520 opacity = colorstop.attribute("stop-opacity").toDouble();
521
522 color.setOpacity(static_cast<quint8>(std::lround(opacity * OPACITY_OPAQUE_U8)));
523 QString stopTypeStr = colorstop.attribute("krita:stop-type", "color-stop");
525 if (stopType != COLORSTOP) {
526 m_hasVariableStops = true;
527 }
528 //According to the SVG spec each gradient offset has to be equal to or greater than the previous one
529 //if not it needs to be adjusted to be equal
530 if (m_stops.count() > 0 && m_stops.last().position >= off) {
531 off = m_stops.last().position;
532 }
533 m_stops.append(KoGradientStop(off, color, stopType));
534 }
535 }
536 if (m_stops.count() >= 2) {
537 setValid(true);
538 } else {
539 setValid(false);
540 }
541}
542
544{
545 return QString(".svg");
546}
547
548void KoStopGradient::toXML(QDomDocument& doc, QDomElement& gradientElt) const
549{
550 gradientElt.setAttribute("type", "stop");
551 for (int s = 0; s < m_stops.size(); s++) {
552 KoGradientStop stop = m_stops.at(s);
553 QDomElement stopElt = doc.createElement("stop");
554 stopElt.setAttribute("offset", KisDomUtils::toString(stop.position));
555 stopElt.setAttribute("bitdepth", stop.color.colorSpace()->colorDepthId().id());
556 stopElt.setAttribute("alpha", KisDomUtils::toString(stop.color.opacityF()));
557 stopElt.setAttribute("stoptype", KisDomUtils::toString(stop.type));
558 stop.color.toXML(doc, stopElt);
559 gradientElt.appendChild(stopElt);
560 }
561}
562
564{
565 KoStopGradient gradient;
567 QDomElement stopElt = elt.firstChildElement("stop");
568 while (!stopElt.isNull()) {
569 qreal offset = KisDomUtils::toDouble(stopElt.attribute("offset", "0.0"));
570 QString bitDepth = stopElt.attribute("bitdepth", Integer8BitsColorDepthID.id());
571 KoColor color = KoColor::fromXML(stopElt.firstChildElement(), bitDepth);
572 color.setOpacity(KisDomUtils::toDouble(stopElt.attribute("alpha", "1.0")));
573 KoGradientStopType stoptype = static_cast<KoGradientStopType>(KisDomUtils::toInt(stopElt.attribute("stoptype", "0")));
574 stops.append(KoGradientStop(offset, color, stoptype));
575 stopElt = stopElt.nextSiblingElement("stop");
576 }
577 gradient.setStops(stops);
578 return gradient;
579}
580
582{
583 QDomDocument doc;
584
585 doc.setContent(QString("<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:krita=\"%1\" > </svg>").arg(KoXmlNS::krita));
586
587 const QString spreadMethod[3] = {
588 QString("pad"),
589 QString("reflect"),
590 QString("repeat")
591 };
592
593 QDomElement gradient = doc.createElement("linearGradient");
594 gradient.setAttribute("id", name());
595 gradient.setAttribute("gradientUnits", "objectBoundingBox");
596 gradient.setAttribute("spreadMethod", spreadMethod[spread()]);
597
598 QHash<QString, const KoColorProfile*> profiles;
599 for(const KoGradientStop & stop: m_stops) {
600 QDomElement stopEl = doc.createElement("stop");
601 stopEl.setAttribute("stop-color", stop.color.toSVG11(&profiles));
602 stopEl.setAttribute("offset", QString().setNum(stop.position));
603 stopEl.setAttribute("stop-opacity", stop.color.opacityF());
604 stopEl.setAttribute("krita:stop-type", stop.typeString());
605 gradient.appendChild(stopEl);
606 }
607
608 if (profiles.size()>0) {
609 QDomElement defs = doc.createElement("defs");
610 for (QString key: profiles.keys()) {
611 const KoColorProfile * profile = profiles.value(key);
612
613 QDomElement profileEl = doc.createElement("color-profile");
614 profileEl.setAttribute("name", key);
615 QString val = profile->uniqueId().toHex();
616 profileEl.setAttribute("local", val);
617 profileEl.setAttribute("xlink:href", profile->fileName());
618 defs.appendChild(profileEl);
619 }
620 doc.documentElement().appendChild(defs);
621 }
622
623 doc.documentElement().appendChild(gradient);
624
625 return doc.toString();
626}
627
628bool KoStopGradient::saveToDevice(QIODevice* dev) const
629{
630 QTextStream stream(dev);
632 stream << saveSvgGradient();
633
634 return true;
635}
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const quint8 OPACITY_OPAQUE_U8
KoGradientStopType
@ FOREGROUNDSTOP
@ BACKGROUNDSTOP
@ COLORSTOP
static KoColorSpaceEngineRegistry * instance()
virtual KoID colorDepthId() const =0
KoMixColorsOp * mixColorsOp
static KoColor fromSVG11(const QString value, QHash< QString, const KoColorProfile * > profileList, KoColor current=KoColor())
fromSVG11 Parses a color attribute value and returns a KoColor. SVG defines the colorprofiles elsewhe...
Definition KoColor.cpp:530
qreal opacityF() const
Definition KoColor.cpp:345
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
Definition KoColor.cpp:350
void toXML(QDomDocument &doc, QDomElement &colorElt) const
Definition KoColor.cpp:304
void setOpacity(quint8 alpha)
Definition KoColor.cpp:333
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
quint8 * data()
Definition KoColor.h:144
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
T get(const QString &id) const
QString id() const
Definition KoID.cpp:63
virtual void mixColors(const quint8 *const *colors, const qint16 *weights, int nColors, quint8 *dst, int weightSum=255) const =0
static QSharedPointer< KoStopGradient > fromQGradient(const QGradient *gradient)
Creates KoStopGradient from a QGradient.
void loadSvgGradient(QIODevice *file)
QString saveSvgGradient() const
QGradient * toQGradient() const override
reimplemented
QString defaultFileExtension() const override
reimplemented
bool stopsAt(KoGradientStop &leftStop, KoGradientStop &rightStop, qreal t) const
Find stops surrounding position, returns false if position outside gradient.
QList< KoGradientStop > m_stops
void colorAt(KoColor &, qreal t) const override
reimplemented
KoResourceSP clone() const override
bool loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface) override
QList< int > requiredCanvasResources() const override
void updateVariableColors(KoCanvasResourcesInterfaceSP canvasResourcesInterface) override
bool saveToDevice(QIODevice *dev) const override
void parseSvgGradient(const QDomElement &element, QHash< QString, const KoColorProfile * > profiles)
void setStops(QList< KoGradientStop > stops)
Sets the gradient stops.
void toXML(QDomDocument &doc, QDomElement &gradientElt) const
toXML Convert the gradient to an XML string.
bool operator==(const KoStopGradient &rhs) const
void bakeVariableColors(KoCanvasResourcesInterfaceSP canvasResourcesInterface) override
static KoStopGradient fromXML(const QDomElement &elt)
fromXML convert a gradient from xml.
KoStopGradient(const QString &filename=QString())
~KoStopGradient() override
QList< KoGradientStop > stops() const
static const QString krita
Definition KoXmlNS.h:48
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
const qint16 qint16_MAX
Definition kis_global.h:28
#define M_PI
Definition kis_global.h:111
QSharedPointer< KoResource > KoResourceSP
double toDouble(const QString &str, bool *ok=nullptr)
int toInt(const QString &str, bool *ok=nullptr)
QString toString(const QString &value)
void setUtf8OnStream(QTextStream &stream)
@ BackgroundColor
The active background color selected for this canvas.
@ ForegroundColor
The active foreground color selected for this canvas.
auto mem_equal_to(MemTypeNoRef Class::*ptr, MemType &&value)
mem_equal_to is an unary functor that compares a member of the object to a given value
Definition KisMpl.h:233
auto mem_less(MemTypeNoRef Class::*ptr, MemType &&value)
mem_less is an unary functor that compares a member of the object to a given value
Definition KisMpl.h:269
void setSpread(QGradient::Spread spreadMethod)
const KoColorSpace * colorSpace
QGradient::Spread spread
void setType(QGradient::Type repeatType)
virtual QByteArray uniqueId() const =0
virtual const KoColorProfile * addProfile(const QString &filename)=0
static KoColorSpaceRegistry * instance()
const KoColorProfile * profileByUniqueId(const QByteArray &id) const
KoGradientStopType type
static KoGradientStopType typeFromString(QString typestring)
void setValid(bool valid)
void setName(const QString &name)
QString name