Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_brush.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 1999 Matthias Elter <me@kde.org>
3 * SPDX-FileCopyrightText: 2003 Patrick Julien <freak@codepimps.org>
4 * SPDX-FileCopyrightText: 2004-2008 Boudewijn Rempt <boud@valdyas.org>
5 * SPDX-FileCopyrightText: 2004 Adrian Page <adrian@pagenet.plus.com>
6 * SPDX-FileCopyrightText: 2005 Bart Coppens <kde@bartcoppens.be>
7 * SPDX-FileCopyrightText: 2007 Cyrille Berger <cberger@cberger.net>
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12#include "kis_brush.h"
13
14#include <QDomElement>
15#include <QFile>
16#include <QPainterPath>
17#include <QPoint>
18#include <QBuffer>
19
20#include <kis_debug.h>
21#include <klocalizedstring.h>
22
23#include <KoColor.h>
24#include <KoColorSpaceMaths.h>
26
27#include "kis_datamanager.h"
28#include "kis_paint_device.h"
29#include "kis_global.h"
30#include "kis_boundary.h"
31#include "kis_image.h"
32#include "kis_iterator_ng.h"
33#include "kis_brush_registry.h"
36#include <kis_qimage_pyramid.h>
40#include <KoResource.h>
45
46
48 qRegisterMetaType<KisBrushSP>("KisBrushSP");
49#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
50 QMetaType::registerEqualsComparator<KisBrushSP>();
51#endif
52}
53
54const QString KisBrush::brushTypeMetaDataKey = "image-based-brush";
55
59
61{
62}
63
67
69{
70 return m_color;
71}
72
76
80
82 : m_source(source)
83 , m_iterator(m_source->createHLineConstIteratorNG(0, 0, width))
84{
85}
86
90
92{
93 return m_iterator->oldRawData();
94}
95
97{
98 m_iterator->nextPixel();
99}
101{
102 m_iterator->nextRow();
103}
104
105namespace detail {
108
109 KisBoundary boundary(dev);
110 boundary.generateBoundary();
111 return new KisOptimizedBrushOutline(boundary.path(), dev->bounds());
112}
113}
114
119 , width(0)
120 , height(0)
121 , spacing (1.0)
122 , hasColor(false)
123 , angle(0)
124 , scale(1.0)
125 , gradient(0)
126 , autoSpacingActive(false)
127 , autoSpacingCoeff(1.0)
128 , threadingAllowed(true)
129 , brushPyramid([] (const KisBrush* brush)
130 {
131 return new KisQImagePyramid(brush->brushTipImage());
132 })
134
135 {
136 }
137
138 Private(const Private &rhs)
139 : brushType(rhs.brushType),
141 width(rhs.width),
142 height(rhs.height),
143 spacing(rhs.spacing),
144 hotSpot(rhs.hotSpot),
145 hasColor(rhs.hasColor),
146 angle(rhs.angle),
147 scale(rhs.scale),
165 {
166 gradient = rhs.gradient;
167 if (rhs.cachedGradient) {
168 cachedGradient = rhs.cachedGradient->clone().staticCast<KoCachedGradient>();
169 }
170 }
171
173 }
174
177
178 qint32 width;
179 qint32 height;
180 double spacing;
181 QPointF hotSpot;
183 qreal angle;
184 qreal scale;
185
188
192
196};
197
199 : KoResource(QString())
200 , d(new Private)
201{
202}
203
204KisBrush::KisBrush(const QString& filename)
205 : KoResource(filename)
206 , d(new Private)
207{
208}
209
211 : KoResource(rhs)
212 , d(new Private(*rhs.d))
213{
214}
215
217{
218 delete d;
219}
220
222{
224 return d->brushTipImage;
225}
226
227qint32 KisBrush::width() const
228{
229 return d->width;
230}
231
232void KisBrush::setWidth(qint32 width)
233{
234 d->width = width;
235}
236
237qint32 KisBrush::height() const
238{
239 return d->height;
240}
241
242void KisBrush::setHeight(qint32 height)
243{
244 d->height = height;
245}
246
247void KisBrush::setHotSpot(QPointF pt)
248{
249 double x = pt.x();
250 double y = pt.y();
251
252 if (x < 0)
253 x = 0;
254 else if (x >= width())
255 x = width() - 1;
256
257 if (y < 0)
258 y = 0;
259 else if (y >= height())
260 y = height() - 1;
261
262 d->hotSpot = QPointF(x, y);
263}
264
265QPointF KisBrush::hotSpot(KisDabShape const& shape, const KisPaintInformation& info) const
266{
267 Q_UNUSED(info);
268
269 QSizeF metric = characteristicSize(shape);
270
271 qreal w = metric.width();
272 qreal h = metric.height();
273
274 // The smallest brush we can produce is a single pixel.
275 if (w < 1) {
276 w = 1;
277 }
278
279 if (h < 1) {
280 h = 1;
281 }
282
283 // XXX: This should take d->hotSpot into account, though it
284 // isn't specified by gimp brushes so it would default to the center
285 // anyway.
286 QPointF p(w / 2, h / 2);
287 return p;
288}
289
297
302
304{
306}
307
309{
310 return d->brushApplication == GRADIENTMAP;
311}
312
314 if (gradient && gradient->valid()) {
315 d->gradient = gradient;
316
317 if (!d->cachedGradient) {
318 d->cachedGradient = toQShared(new KoCachedGradient(d->gradient, 256, d->gradient->colorSpace()));
319 } else {
320 d->cachedGradient->setGradient(d->gradient, 256, d->gradient->colorSpace());
321 }
322 }
323}
324
326{
327 QImage image = brushTipImage();
328
329 qreal w = image.width();
330 qreal h = image.height();
331
332 if (w < 3 && h < 3) { return false; }
333
334 qreal xPortion = qMin(0.1, 5.0 / w);
335 qreal yPortion = qMin(0.1, 5.0 / h);
336
337 int x0 = std::floor((0.5 - xPortion) * w);
338 int x1 = std::ceil((0.5 + xPortion) * w);
339
340 int y0 = std::floor((0.5 - yPortion) * h);
341 int y1 = std::ceil((0.5 + yPortion) * h);
342
343 const int maxNumSamples = (x1 - x0 + 1) * (y1 - y0 + 1);
344 const int failedPixelsThreshold = 0.1 * maxNumSamples;
345 const int thresholdValue = 0.95 * 255;
346 int failedPixels = 0;
347
348 for (int y = y0; y <= y1; y++) {
349 for (int x = x0; x <= x1; x++) {
350 QRgb pixel = image.pixel(x,y);
351
352 if (qRed(pixel) > thresholdValue) {
353 failedPixels++;
354 }
355 }
356 }
357
358 return failedPixels > failedPixelsThreshold;
359}
360
361namespace {
362void fetchPremultipliedRed(const QRgb* src, quint8 *dst, int maskWidth)
363{
364 for (int x = 0; x < maskWidth; x++) {
365 *dst = KoColorSpaceMaths<quint8>::multiply(255 - *src, qAlpha(*src));
366 src++;
367 dst++;
368 }
369}
370}
371
373{
381 const QImage image = brushTipImage().convertToFormat(QImage::Format_ARGB32);
382
383 dev->setRect(image.rect());
385
386 const int maskWidth = image.width();
387 const int maskHeight = image.height();
388
389 quint8 *dstPtr = dev->data();
390
391 for (int y = 0; y < maskHeight; y++) {
392 const QRgb* maskPointer = reinterpret_cast<const QRgb*>(image.constScanLine(y));
393 fetchPremultipliedRed(maskPointer, dstPtr, maskWidth);
394 dstPtr += maskWidth;
395 }
396
397 return dev;
398}
399
401{
402 return true;
403}
404
405void KisBrush::setBrushTipImage(const QImage& image)
406{
408
409 if (!image.isNull()) {
410 if (image.width() > 128 || image.height() > 128) {
411 KoResource::setImage(image.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation));
412 }
413 else {
415 }
416 setWidth(image.width());
417 setHeight(image.height());
418 }
421}
422
424{
425 d->brushType = type;
427 QVariant::fromValue(type == IMAGE || type == PIPE_IMAGE));
428}
429
431{
432 return d->brushType;
433}
434
435void KisBrush::predefinedBrushToXML(const QString &type, QDomElement& e) const
436{
437 e.setAttribute("type", type);
438 e.setAttribute("filename", filename());
439 e.setAttribute("md5sum", md5Sum());
440 e.setAttribute("spacing", QString::number(spacing()));
441 e.setAttribute("useAutoSpacing", QString::number(autoSpacingActive()));
442 e.setAttribute("autoSpacingCoeff", QString::number(autoSpacingCoeff()));
443 e.setAttribute("angle", QString::number(angle()));
444 e.setAttribute("scale", QString::number(scale()));
445 e.setAttribute("brushApplication", QString::number((int)brushApplication()));
446}
447
448void KisBrush::toXML(QDomDocument& /*document*/ , QDomElement& element) const
449{
450 element.setAttribute("BrushVersion", "2");
451}
452
453KisBrushSP KisBrush::fromXML(const QDomElement& element, KisResourcesInterfaceSP resourcesInterface)
454{
455 KoResourceLoadResult result = fromXMLLoadResult(element, resourcesInterface);
456
457 KisBrushSP brush = result.resource<KisBrush>();
458 if (!brush) {
459 QDomElement el;
460 brush = KisBrushRegistry::instance()->get("auto_brush")->createBrush(el, resourcesInterface).resource<KisBrush>();
461 }
462 return brush;
463}
464
465KoResourceLoadResult KisBrush::fromXMLLoadResult(const QDomElement& element, KisResourcesInterfaceSP resourcesInterface)
466{
467 KoResourceLoadResult result = KisBrushRegistry::instance()->createBrush(element, resourcesInterface);
468
469 KisBrushSP brush = result.resource<KisBrush>();
470 if (brush && element.attribute("BrushVersion", "1") == "1") {
471 brush->setScale(brush->scale() * 2.0);
472 }
473
474 return result;
475}
476
478{
479 KisDabShape normalizedShape(
480 shape.scale() * d->scale,
481 shape.ratio(),
482 normalizeAngle(shape.rotation() + d->angle));
484 QSize(width(), height()), normalizedShape);
485}
486
487qint32 KisBrush::maskWidth(KisDabShape const& shape, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const
488{
489 Q_UNUSED(info);
490
491 qreal angle = normalizeAngle(shape.rotation() + d->angle);
492 qreal scale = shape.scale() * d->scale;
493
494 return KisQImagePyramid::imageSize(QSize(width(), height()),
495 KisDabShape(scale, shape.ratio(), angle),
496 subPixelX, subPixelY).width();
497}
498
499qint32 KisBrush::maskHeight(KisDabShape const& shape, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const
500{
501 Q_UNUSED(info);
502
503 qreal angle = normalizeAngle(shape.rotation() + d->angle);
504 qreal scale = shape.scale() * d->scale;
505
506 return KisQImagePyramid::imageSize(QSize(width(), height()),
507 KisDabShape(scale, shape.ratio(), angle),
508 subPixelX, subPixelY).height();
509}
510
511double KisBrush::maskAngle(double angle) const
512{
513 return normalizeAngle(angle + d->angle);
514}
515
516quint32 KisBrush::brushIndex() const
517{
518 return 0;
519}
520
522{
523 if (s < 0.02) s = 0.02;
524 d->spacing = s;
525}
526
527double KisBrush::spacing() const
528{
529 return d->spacing;
530}
531
532void KisBrush::setAutoSpacing(bool active, qreal coeff)
533{
534 d->autoSpacingCoeff = coeff;
536}
537
539{
540 return d->autoSpacingActive;
541}
542
544{
545 return d->autoSpacingCoeff;
546}
547
551
553{
556 d->brushPyramid.initialize(this);
557}
558
560{
561 Q_UNUSED(info);
562 Q_UNUSED(seqNo);
563}
564
566{
567 d->brushPyramid.reset();
568}
569
570void KisBrush::mask(KisFixedPaintDeviceSP dst, const KoColor& color, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY, qreal softnessFactor, qreal lightnessStrength) const
571{
572 PlainColoringInformation pci(color.data());
573 generateMaskAndApplyMaskOrCreateDab(dst, &pci, shape, info, subPixelX, subPixelY, softnessFactor, lightnessStrength);
574}
575
576void KisBrush::mask(KisFixedPaintDeviceSP dst, const KisPaintDeviceSP src, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY, qreal softnessFactor, qreal lightnessStrength) const
577{
578 PaintDeviceColoringInformation pdci(src, maskWidth(shape, subPixelX, subPixelY, info));
579 generateMaskAndApplyMaskOrCreateDab(dst, &pdci, shape, info, subPixelX, subPixelY, softnessFactor, lightnessStrength);
580}
581
583 ColoringInformation* coloringInformation,
584 KisDabShape const& shape,
585 const KisPaintInformation& info_,
586 double subPixelX, double subPixelY, qreal softnessFactor) const
587{
588 generateMaskAndApplyMaskOrCreateDab(dst, coloringInformation, shape, info_, subPixelX, subPixelY, softnessFactor, DEFAULT_LIGHTNESS_STRENGTH);
589}
590
592 ColoringInformation* coloringInformation,
593 KisDabShape const& shape,
594 const KisPaintInformation& info_,
595 double subPixelX, double subPixelY, qreal softnessFactor, qreal lightnessStrength) const
596{
598 Q_UNUSED(info_);
599 Q_UNUSED(softnessFactor);
600
601 QImage outputImage = d->brushPyramid.value(this)->createImage(KisDabShape(
602 shape.scale() * d->scale, shape.ratio(),
603 -normalizeAngle(shape.rotation() + d->angle)),
604 subPixelX, subPixelY);
605
606 qint32 maskWidth = outputImage.width();
607 qint32 maskHeight = outputImage.height();
608
609 dst->setRect(QRect(0, 0, maskWidth, maskHeight));
611
612 KIS_SAFE_ASSERT_RECOVER_RETURN(coloringInformation);
613
614 quint8* color = 0;
615 if (dynamic_cast<PlainColoringInformation*>(coloringInformation)) {
616 color = const_cast<quint8*>(coloringInformation->color());
617 }
618
619 const KoColorSpace *cs = dst->colorSpace();
620 const quint32 pixelSize = cs->pixelSize();
621 const quint32 maskPixelSize = sizeof(QRgb);
622 quint8 *rowPointer = dst->data();
623
624 const bool preserveLightness = this->preserveLightness();
625 bool applyGradient = this->applyingGradient();
626 QScopedPointer<KoColor> fallbackColor;
627
628 if (applyGradient) {
629 if (d->cachedGradient) {
631 d->cachedGradient->setColorSpace(cs); //convert gradient to colorspace so we don't have to convert each pixel
632 } else {
633 fallbackColor.reset(new KoColor(Qt::red, cs));
634 color = fallbackColor->data();
635 applyGradient = false;
636 }
637 }
638
639 KoColor gradientcolor(Qt::blue, cs);
640 for (int y = 0; y < maskHeight; y++) {
641 const quint8* maskPointer = outputImage.constScanLine(y);
642 if (color) {
643 if (preserveLightness) {
644 cs->fillGrayBrushWithColorAndLightnessWithStrength(rowPointer, reinterpret_cast<const QRgb*>(maskPointer), color, lightnessStrength, maskWidth);
645 }
646 else if (applyGradient) {
647 quint8* pixel = rowPointer;
648 for (int x = 0; x < maskWidth; x++) {
649 const QRgb* maskQRgb = reinterpret_cast<const QRgb*>(maskPointer);
650 qreal maskOpacity = qreal(qAlpha(*maskQRgb)) / 255.0;
651 if (maskOpacity > 0) {
652 qreal gradientvalue = qreal(qGray(*maskQRgb)) / 255.0;
653 gradientcolor.setColor(d->cachedGradient->cachedAt(gradientvalue), cs);
654 }
655 qreal gradientOpacity = gradientcolor.opacityF();
656 qreal opacity = gradientOpacity * maskOpacity;
657 gradientcolor.setOpacity(opacity);
658 memcpy(pixel, gradientcolor.data(), pixelSize);
659
660 maskPointer += maskPixelSize;
661 pixel += pixelSize;
662 }
663 }
664 else {
665 cs->fillGrayBrushWithColor(rowPointer, reinterpret_cast<const QRgb*>(maskPointer), color, maskWidth);
666 }
667 }
668 else {
669 {
670 quint8 *dst = rowPointer;
671 for (int x = 0; x < maskWidth; x++) {
672 memcpy(dst, coloringInformation->color(), pixelSize);
673 coloringInformation->nextColumn();
674 dst += pixelSize;
675 }
676 }
677
678 QScopedArrayPointer<quint8> alphaArray(new quint8[maskWidth]);
679 fetchPremultipliedRed(reinterpret_cast<const QRgb*>(maskPointer), alphaArray.data(), maskWidth);
680 cs->applyAlphaU8Mask(rowPointer, alphaArray.data(), maskWidth);
681 }
682
683 rowPointer += maskWidth * pixelSize;
684
685 if (!color) {
686 coloringInformation->nextRow();
687 }
688 }
689
690
691}
692
694 KisDabShape const& shape,
695 const KisPaintInformation& info,
696 double subPixelX, double subPixelY) const
697{
698 Q_ASSERT(valid());
699 Q_UNUSED(info);
700 double angle = normalizeAngle(shape.rotation() + d->angle);
701 double scale = shape.scale() * d->scale;
702
703 QImage outputImage = d->brushPyramid.value(this)->createImage(
704 KisDabShape(scale, shape.ratio(), -angle), subPixelX, subPixelY);
705
706 KisFixedPaintDeviceSP dab = new KisFixedPaintDevice(colorSpace);
707 Q_CHECK_PTR(dab);
708 dab->convertFromQImage(outputImage, "");
709
710 return dab;
711}
712
714{
715 d->brushOutline.reset();
716}
717
719{
720 d->brushOutline.initialize(this);
721}
722
724{
725 return !d->brushOutline.isNull();
726}
727
728void KisBrush::setScale(qreal _scale)
729{
730 d->scale = _scale;
731}
732
733qreal KisBrush::scale() const
734{
735 return d->scale;
736}
737
738void KisBrush::setAngle(qreal _rotation)
739{
740 d->angle = _rotation;
741}
742
743qreal KisBrush::angle() const
744{
745 return d->angle;
746}
747
748KisOptimizedBrushOutline KisBrush::outline(bool forcePreciseOutline) const
749{
750 Q_UNUSED(forcePreciseOutline);
751
752 return *d->brushOutline.value(this);
753}
754
756{
757 if (spacing() > 0.5) {
758 l->limitations << KoID("huge-spacing", i18nc("PaintOp instant preview limitation", "Spacing > 0.5, consider disabling Instant Preview"));
759 }
760}
761
763{
764 return true;
765}
766
768{
769 d->brushPyramid.initialize(this);
771}
const Params2D p
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
void generateBoundary()
QPainterPath path() const
returns the outline saved in QPainterPath
virtual KoResourceLoadResult createBrush(const QDomElement &element, KisResourcesInterfaceSP resourcesInterface)=0
static KisBrushRegistry * instance()
KoResourceLoadResult createBrush(const QDomElement &element, KisResourcesInterfaceSP resourcesInterface)
virtual const quint8 * color() const =0
const quint8 * color() const override
Definition kis_brush.cpp:91
PaintDeviceColoringInformation(const KisPaintDeviceSP source, int width)
Definition kis_brush.cpp:81
const quint8 * color() const override
Definition kis_brush.cpp:68
PlainColoringInformation(const quint8 *color)
Definition kis_brush.cpp:60
virtual void setGradient(KoAbstractGradientSP gradient)
static const QString brushTypeMetaDataKey
Definition kis_brush.h:343
virtual qint32 maskHeight(KisDabShape const &, qreal subPixelX, qreal subPixelY, const KisPaintInformation &info) const
bool outlineCacheIsValid() const
virtual enumBrushApplication brushApplication() const
virtual enumBrushType brushType() const
virtual void setSpacing(double spacing)
qint32 width() const
virtual void lodLimitations(KisPaintopLodLimitations *l) const
virtual void setAngle(qreal _angle)
virtual QImage brushTipImage() const
brushImage the image the brush tip can paint with. Not all brush types have a single image.
virtual void setBrushType(enumBrushType type)
double maskAngle(double angle=0) const
virtual void notifyStrokeStarted()
virtual void setScale(qreal _scale)
void predefinedBrushToXML(const QString &type, QDomElement &e) const
void setHotSpot(QPointF)
bool autoSpacingActive() const
void resetOutlineCache()
Private *const d
Definition kis_brush.h:387
double spacing() const
~KisBrush() override
virtual bool applyingGradient() const
QPointF hotSpot(KisDabShape const &, const KisPaintInformation &info) const
virtual void coldInitBrush()
virtual KisFixedPaintDeviceSP paintDevice(const KoColorSpace *colorSpace, KisDabShape const &, const KisPaintInformation &info, double subPixelX=0, double subPixelY=0) const
void mask(KisFixedPaintDeviceSP dst, const KoColor &color, KisDabShape const &shape, const KisPaintInformation &info, double subPixelX=0, double subPixelY=0, qreal softnessFactor=DEFAULT_SOFTNESS_FACTOR, qreal lightnessStrength=DEFAULT_LIGHTNESS_STRENGTH) const
void setAutoSpacing(bool active, qreal coeff)
virtual bool preserveLightness() const
static KisBrushSP fromXML(const QDomElement &element, KisResourcesInterfaceSP resourcesInterface)
virtual KisFixedPaintDeviceSP outlineSourceImage() const
virtual void prepareForSeqNo(const KisPaintInformation &info, int seqNo)
void generateOutlineCache()
virtual QSizeF characteristicSize(KisDabShape const &) const
virtual void toXML(QDomDocument &, QDomElement &) const
virtual bool supportsCaching() const
virtual void notifyBrushIsGoingToBeClonedForStroke()
static KoResourceLoadResult fromXMLLoadResult(const QDomElement &element, KisResourcesInterfaceSP resourcesInterface)
virtual void setBrushTipImage(const QImage &image)
virtual KisOptimizedBrushOutline outline(bool forcePreciseOutline=false) const
virtual bool isPiercedApprox() const
qreal autoSpacingCoeff() const
void setWidth(qint32 width)
void clearBrushPyramid()
virtual void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, ColoringInformation *coloringInfo, KisDabShape const &, const KisPaintInformation &info, double subPixelX, double subPixelY, qreal softnessFactor, qreal lightnessStrength) const
qint32 height() const
void setHeight(qint32 height)
virtual quint32 brushIndex() const
qreal scale() const
virtual void setBrushApplication(enumBrushApplication brushApplication)
virtual qint32 maskWidth(KisDabShape const &, qreal subPixelX, qreal subPixelY, const KisPaintInformation &info) const
virtual bool canPaintFor(const KisPaintInformation &)
qreal angle() const
qreal scale() const
qreal rotation() const
qreal ratio() const
void setRect(const QRect &rc)
virtual void convertFromQImage(const QImage &image, const QString &srcProfileName)
const KoColorSpace * colorSpace() const
static QSize imageSize(const QSize &originalSize, KisDabShape const &, qreal subPixelX, qreal subPixelY)
static QSizeF characteristicSize(const QSize &originalSize, KisDabShape const &)
static _Tdst multiply(_T a, _Tdst b)
virtual quint32 pixelSize() const =0
virtual void applyAlphaU8Mask(quint8 *pixels, const quint8 *alpha, qint32 nPixels) const =0
virtual void fillGrayBrushWithColor(quint8 *dst, const QRgb *brush, quint8 *brushColor, qint32 nPixels) const =0
virtual void fillGrayBrushWithColorAndLightnessWithStrength(quint8 *dst, const QRgb *brush, quint8 *brushColor, qreal strength, qint32 nPixels) const
qreal opacityF() const
Definition KoColor.cpp:345
void setColor(const quint8 *data, const KoColorSpace *colorSpace=0)
Definition KoColor.cpp:186
void setOpacity(quint8 alpha)
Definition KoColor.cpp:333
quint8 * data()
Definition KoColor.h:144
T get(const QString &id) const
Definition KoID.h:30
KoResourceSP resource() const noexcept
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
KIS_DECLARE_STATIC_INITIALIZER
Definition kis_brush.cpp:47
enumBrushType
Definition kis_brush.h:30
@ IMAGE
Definition kis_brush.h:33
@ PIPE_IMAGE
Definition kis_brush.h:35
@ INVALID
Definition kis_brush.h:31
static const qreal DEFAULT_LIGHTNESS_STRENGTH
Definition kis_brush.h:46
enumBrushApplication
Definition kis_brush.h:38
@ ALPHAMASK
Definition kis_brush.h:39
@ GRADIENTMAP
Definition kis_brush.h:42
@ LIGHTNESSMAP
Definition kis_brush.h:41
unsigned int QRgb
std::enable_if< std::is_floating_point< T >::value, T >::type normalizeAngle(T a)
Definition kis_global.h:121
QSharedPointer< T > toQShared(T *ptr)
KisOptimizedBrushOutline * outlineFactory(const KisBrush *brush)
KoAbstractGradientSP gradient
enumBrushType brushType
Private(const Private &rhs)
enumBrushApplication brushApplication
QSharedPointer< KoCachedGradient > cachedGradient
KisLazySharedCacheStorageLinked< KisOptimizedBrushOutline, const KisBrush * > brushOutline
KisLazySharedCacheStorageLinked< KisQImagePyramid, const KisBrush * > brushPyramid
static KoColorSpaceRegistry * instance()
const KoColorSpace * alpha8()
void addMetaData(QString key, QVariant value)
store the given key, value pair in the resource
QImage image
QString filename
void setImage(const QImage &image)
QString md5Sum(bool generateIfEmpty=true) const