16#include <QPainterPath>
21#include <klocalizedstring.h>
48 qRegisterMetaType<KisBrushSP>(
"KisBrushSP");
49#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
50 QMetaType::registerEqualsComparator<KisBrushSP>();
83 , m_iterator(m_source->createHLineConstIteratorNG(0, 0,
width))
93 return m_iterator->oldRawData();
98 m_iterator->nextPixel();
102 m_iterator->nextRow();
254 else if (x >=
width())
271 qreal w = metric.width();
272 qreal h = metric.height();
286 QPointF
p(w / 2, h / 2);
314 if (gradient && gradient->valid()) {
329 qreal w =
image.width();
330 qreal h =
image.height();
332 if (w < 3 && h < 3) {
return false; }
334 qreal xPortion = qMin(0.1, 5.0 / w);
335 qreal yPortion = qMin(0.1, 5.0 / h);
337 int x0 = std::floor((0.5 - xPortion) * w);
338 int x1 = std::ceil((0.5 + xPortion) * w);
340 int y0 = std::floor((0.5 - yPortion) * h);
341 int y1 = std::ceil((0.5 + yPortion) * h);
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;
348 for (
int y = y0; y <= y1; y++) {
349 for (
int x = x0; x <= x1; x++) {
352 if (qRed(pixel) > thresholdValue) {
358 return failedPixels > failedPixelsThreshold;
362void fetchPremultipliedRed(
const QRgb* src, quint8 *dst,
int maskWidth)
364 for (
int x = 0; x < maskWidth; x++) {
389 quint8 *dstPtr = dev->
data();
392 const QRgb* maskPointer =
reinterpret_cast<const QRgb*
>(
image.constScanLine(y));
393 fetchPremultipliedRed(maskPointer, dstPtr,
maskWidth);
409 if (!
image.isNull()) {
410 if (
image.width() > 128 ||
image.height() > 128) {
437 e.setAttribute(
"type", type);
438 e.setAttribute(
"filename",
filename());
439 e.setAttribute(
"md5sum",
md5Sum());
440 e.setAttribute(
"spacing", QString::number(
spacing()));
443 e.setAttribute(
"angle", QString::number(
angle()));
444 e.setAttribute(
"scale", QString::number(
scale()));
445 e.setAttribute(
"brushApplication", QString::number((
int)
brushApplication()));
450 element.setAttribute(
"BrushVersion",
"2");
470 if (brush && element.attribute(
"BrushVersion",
"1") ==
"1") {
471 brush->setScale(brush->scale() * 2.0);
496 subPixelX, subPixelY).width();
508 subPixelX, subPixelY).height();
523 if (s < 0.02) s = 0.02;
586 double subPixelX,
double subPixelY, qreal softnessFactor)
const
595 double subPixelX,
double subPixelY, qreal softnessFactor, qreal lightnessStrength)
const
599 Q_UNUSED(softnessFactor);
604 subPixelX, subPixelY);
616 color =
const_cast<quint8*
>(coloringInformation->
color());
620 const quint32 pixelSize = cs->
pixelSize();
621 const quint32 maskPixelSize =
sizeof(
QRgb);
622 quint8 *rowPointer = dst->
data();
626 QScopedPointer<KoColor> fallbackColor;
633 fallbackColor.reset(
new KoColor(Qt::red, cs));
634 color = fallbackColor->data();
635 applyGradient =
false;
639 KoColor gradientcolor(Qt::blue, cs);
641 const quint8* maskPointer = outputImage.constScanLine(y);
646 else if (applyGradient) {
647 quint8* pixel = rowPointer;
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;
655 qreal gradientOpacity = gradientcolor.
opacityF();
656 qreal opacity = gradientOpacity * maskOpacity;
658 memcpy(pixel, gradientcolor.
data(), pixelSize);
660 maskPointer += maskPixelSize;
670 quint8 *dst = rowPointer;
672 memcpy(dst, coloringInformation->
color(), pixelSize);
678 QScopedArrayPointer<quint8> alphaArray(
new quint8[
maskWidth]);
679 fetchPremultipliedRed(
reinterpret_cast<const QRgb*
>(maskPointer), alphaArray.data(),
maskWidth);
686 coloringInformation->
nextRow();
696 double subPixelX,
double subPixelY)
const
703 QImage outputImage =
d->
brushPyramid.value(
this)->createImage(
750 Q_UNUSED(forcePreciseOutline);
758 l->
limitations <<
KoID(
"huge-spacing", i18nc(
"PaintOp instant preview limitation",
"Spacing > 0.5, consider disabling Instant Preview"));
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
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 void setGradient(KoAbstractGradientSP gradient)
static const QString brushTypeMetaDataKey
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)
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
bool autoSpacingActive() const
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)
virtual void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, ColoringInformation *coloringInfo, KisDabShape const &, const KisPaintInformation &info, double subPixelX, double subPixelY, qreal softnessFactor, qreal lightnessStrength) const
void setHeight(qint32 height)
virtual quint32 brushIndex() const
virtual void setBrushApplication(enumBrushApplication brushApplication)
virtual qint32 maskWidth(KisDabShape const &, qreal subPixelX, qreal subPixelY, const KisPaintInformation &info) const
virtual bool canPaintFor(const KisPaintInformation &)
void setRect(const QRect &rc)
void lazyGrowBufferWithoutInitialization()
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
void setColor(const quint8 *data, const KoColorSpace *colorSpace=0)
void setOpacity(quint8 alpha)
T get(const QString &id) const
KoResourceSP resource() const noexcept
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
KIS_DECLARE_STATIC_INITIALIZER
static const qreal DEFAULT_LIGHTNESS_STRENGTH
std::enable_if< std::is_floating_point< T >::value, T >::type normalizeAngle(T a)
QSharedPointer< T > toQShared(T *ptr)
KisOptimizedBrushOutline * outlineFactory(const KisBrush *brush)
KoAbstractGradientSP gradient
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
void setImage(const QImage &image)
QString md5Sum(bool generateIfEmpty=true) const