Krita Source Code Documentation
Loading...
Searching...
No Matches
KisPredefinedBrushFactory Class Reference

#include <kis_predefined_brush_factory.h>

+ Inheritance diagram for KisPredefinedBrushFactory:

Public Member Functions

KoResourceLoadResult createBrush (const KisBrushModel::BrushData &brushData, KisResourcesInterfaceSP resourcesInterface) override
 
KoResourceLoadResult createBrush (const QDomElement &brushDefinition, KisResourcesInterfaceSP resourcesInterface) override
 
std::optional< KisBrushModel::BrushDatacreateBrushModel (const QDomElement &element, KisResourcesInterfaceSP resourcesInterface) override
 
QString id () const override
 
 KisPredefinedBrushFactory (const QString &brushType)
 
void toXML (QDomDocument &doc, QDomElement &element, const KisBrushModel::BrushData &model) override
 
- Public Member Functions inherited from KisBrushFactory
 KisBrushFactory ()
 
virtual QString name () const
 
virtual ~KisBrushFactory ()
 

Static Public Member Functions

static void loadFromBrushResource (KisBrushModel::CommonData &commonData, KisBrushModel::PredefinedBrushData &predefinedBrushData, KisBrushSP brushResource)
 

Private Member Functions

std::variant< KisBrushModel::BrushData, KoResourceSignaturecreateBrushModelImpl (const QDomElement &element, KisResourcesInterfaceSP resourcesInterface)
 

Private Attributes

const QString m_id
 

Detailed Description

Definition at line 18 of file kis_predefined_brush_factory.h.

Constructor & Destructor Documentation

◆ KisPredefinedBrushFactory()

KisPredefinedBrushFactory::KisPredefinedBrushFactory ( const QString & brushType)

Definition at line 20 of file kis_predefined_brush_factory.cpp.

21 : m_id(brushType)
22{
23}

Member Function Documentation

◆ createBrush() [1/2]

KoResourceLoadResult KisPredefinedBrushFactory::createBrush ( const KisBrushModel::BrushData & brushData,
KisResourcesInterfaceSP resourcesInterface )
overridevirtual

Implements KisBrushFactory.

Definition at line 30 of file kis_predefined_brush_factory.cpp.

31{
32 auto resourceSourceAdapter = resourcesInterface->source<KisBrush>(ResourceType::Brushes);
33 const QString brushFileName = brushData.predefinedBrush.resourceSignature.filename;
34 const QString brushMD5Sum = brushData.predefinedBrush.resourceSignature.md5sum;
35 KisBrushSP brush = resourceSourceAdapter.bestMatch(brushMD5Sum, brushFileName, "");
36 if (!brush) {
37 return KoResourceSignature(ResourceType::Brushes, brushMD5Sum, brushFileName, "");
38 }
39
40 // we always return a copy of the brush!
41 brush = brush->clone().dynamicCast<KisBrush>();
42
43 brush->setSpacing(brushData.common.spacing);
44 brush->setAutoSpacing(brushData.common.useAutoSpacing, brushData.common.autoSpacingCoeff);
45 brush->setAngle(brushData.common.angle);
46 brush->setScale(brushData.predefinedBrush.scale);
47
48 KisColorfulBrush *colorfulBrush = dynamic_cast<KisColorfulBrush*>(brush.data());
49 if (colorfulBrush) {
54 }
55
56 brush->setBrushApplication(brushData.predefinedBrush.application);
57
58 return brush;
59}
virtual void setAdjustmentMidPoint(quint8 value)
virtual void setContrastAdjustment(qreal value)
virtual void setBrightnessAdjustment(qreal value)
virtual void setAutoAdjustMidPoint(bool autoAdjustMidPoint)
A simple wrapper object for the main information about the resource.
const QString Brushes
PredefinedBrushData predefinedBrush
KoResourceSignature resourceSignature

References KisBrushModel::PredefinedBrushData::adjustmentMidPoint, KisBrushModel::CommonData::angle, KisBrushModel::PredefinedBrushData::application, KisBrushModel::PredefinedBrushData::autoAdjustMidPoint, KisBrushModel::CommonData::autoSpacingCoeff, KisBrushModel::PredefinedBrushData::brightnessAdjustment, ResourceType::Brushes, KisBrushModel::BrushData::common, KisBrushModel::PredefinedBrushData::contrastAdjustment, KoResourceSignature::filename, KoResourceSignature::md5sum, KisBrushModel::BrushData::predefinedBrush, KisBrushModel::PredefinedBrushData::resourceSignature, KisBrushModel::PredefinedBrushData::scale, KisColorfulBrush::setAdjustmentMidPoint(), KisColorfulBrush::setAutoAdjustMidPoint(), KisColorfulBrush::setBrightnessAdjustment(), KisColorfulBrush::setContrastAdjustment(), KisBrushModel::CommonData::spacing, and KisBrushModel::CommonData::useAutoSpacing.

◆ createBrush() [2/2]

KoResourceLoadResult KisPredefinedBrushFactory::createBrush ( const QDomElement & element,
KisResourcesInterfaceSP resourcesInterface )
overridevirtual

Create a new brush from the given data or return an existing KisBrush object. If this call leads to the creation of a resource, it should be added to the resource provider, too.

Implements KisBrushFactory.

Definition at line 61 of file kis_predefined_brush_factory.cpp.

62{
63 auto data = createBrushModelImpl(brushDefinition, resourcesInterface);
64
65 if (std::holds_alternative<KisBrushModel::BrushData>(data)) {
66 return createBrush(std::get<KisBrushModel::BrushData>(data), resourcesInterface);
67 } else if (std::holds_alternative<KoResourceSignature>(data)) {
68 return std::get<KoResourceSignature>(data);
69 }
70
71 // fallback, should never reach!
73}
std::variant< KisBrushModel::BrushData, KoResourceSignature > createBrushModelImpl(const QDomElement &element, KisResourcesInterfaceSP resourcesInterface)
KoResourceLoadResult createBrush(const KisBrushModel::BrushData &brushData, KisResourcesInterfaceSP resourcesInterface) override

References ResourceType::Brushes, createBrush(), and createBrushModelImpl().

◆ createBrushModel()

std::optional< KisBrushModel::BrushData > KisPredefinedBrushFactory::createBrushModel ( const QDomElement & element,
KisResourcesInterfaceSP resourcesInterface )
overridevirtual

Implements KisBrushFactory.

Definition at line 75 of file kis_predefined_brush_factory.cpp.

76{
77 auto data = createBrushModelImpl(element, resourcesInterface);
78 return std::holds_alternative<KisBrushModel::BrushData>(data) ?
79 std::make_optional(std::get<KisBrushModel::BrushData>(data)) :
80 std::nullopt;
81}

References createBrushModelImpl().

◆ createBrushModelImpl()

std::variant< KisBrushModel::BrushData, KoResourceSignature > KisPredefinedBrushFactory::createBrushModelImpl ( const QDomElement & element,
KisResourcesInterfaceSP resourcesInterface )
private

we should first initialize data from the brush, because it may change the spacing properties embedded into some brushes

In Krita 4.x releases there was a bug that caused lightness adjustments to be applied to the brush twice. It happened due to the fact that copy-ctor called brushTipImage() virtual method instead of just copying the image itself.

In Krita 5 we should open these brushes in somewhat the same way. The problem is that we cannot convert the numbers precisely, because after applying a piecewise-linear function twice we get a quadratic function. So we fall-back to a blunt parameters scaling, which gives result that is just "good enough".

NOTE: AutoAdjustMidPoint option appeared only in Krita 5, so it automatically means the adjustments should be applied in the new way.

In Krita we also changed formula for contrast calculation in negative part, so we need to convert that as well.

In Krita versions before 4.4 series "ColorAsMask" could be overridden to false when the brush had no color inside. That changed in Krita 4.4.x series, when "brushApplication" replaced all the automatic heuristics

In Krita versions before 4.4 series we used to automatically select the brush application depending on the presence of the color in the brush, even when there was no "ColorAsMask" field.

Definition at line 83 of file kis_predefined_brush_factory.cpp.

84{
86
87 auto resourceSourceAdapter = resourcesInterface->source<KisBrush>(ResourceType::Brushes);
88 const QString brushFileName = element.attribute("filename", "");
89 const QString brushMD5Sum = element.attribute("md5sum", "");
90 KisBrushSP brushResource = resourceSourceAdapter.bestMatch(brushMD5Sum, brushFileName, "");
91 if (!brushResource) {
92 return KoResourceSignature(ResourceType::Brushes, brushMD5Sum, brushFileName, "");
93 }
94
96
99 loadFromBrushResource(brush.common, brush.predefinedBrush, brushResource);
100
101 brush.common.angle = KisDomUtils::toDouble(element.attribute("angle", "0.0"));
102 brush.common.spacing = KisDomUtils::toDouble(element.attribute("spacing", "0.25"));
103 brush.common.useAutoSpacing = KisDomUtils::toInt(element.attribute("useAutoSpacing", "0"));
104 brush.common.autoSpacingCoeff = KisDomUtils::toDouble(element.attribute("autoSpacingCoeff", "1.0"));
105
106 brush.predefinedBrush.scale = KisDomUtils::toDouble(element.attribute("scale", "1.0"));
107
108 // legacy support...
109 if (element.attribute("BrushVersion", "1") == "1") {
110 brush.predefinedBrush.scale *= 2.0;
111 }
112
113 KisColorfulBrush *colorfulBrush = dynamic_cast<KisColorfulBrush*>(brushResource.data());
114 if (colorfulBrush) {
115 quint8 adjustmentMidPoint = element.attribute("AdjustmentMidPoint", "127").toInt();
116 qreal brightnessAdjustment = element.attribute("BrightnessAdjustment").toDouble();
117 qreal contrastAdjustment = element.attribute("ContrastAdjustment").toDouble();
118
119 const int adjustmentVersion = element.attribute("AdjustmentVersion", "1").toInt();
120 const bool autoAdjustMidPoint = element.attribute("AutoAdjustMidPoint", "0").toInt();
121 const bool hasAutoAdjustMidPoint = element.hasAttribute("AutoAdjustMidPoint");
122
138 if (adjustmentVersion < 2 && !hasAutoAdjustMidPoint) {
139 adjustmentMidPoint = qBound(0, 127 + (int(adjustmentMidPoint) - 127) * 2, 255);
140 brightnessAdjustment *= 2.0;
141 contrastAdjustment *= 2.0;
142
147 if (contrastAdjustment < 0) {
148 contrastAdjustment = 1.0 / (1.0 - contrastAdjustment) - 1.0;
149 }
150 }
151
152 brush.predefinedBrush.adjustmentMidPoint = adjustmentMidPoint;
153 brush.predefinedBrush.brightnessAdjustment = brightnessAdjustment;
154 brush.predefinedBrush.contrastAdjustment = contrastAdjustment;
155 brush.predefinedBrush.autoAdjustMidPoint = autoAdjustMidPoint;
157 }
158
159 auto legacyBrushApplication = [] (KisColorfulBrush *colorfulBrush, bool forceColorToAlpha) {
166 return (colorfulBrush && colorfulBrush->hasColorAndTransparency() && !forceColorToAlpha) ? IMAGESTAMP : ALPHAMASK;
167 };
168
169
170 if (element.hasAttribute("preserveLightness")) {
171 const int preserveLightness = KisDomUtils::toInt(element.attribute("preserveLightness", "0"));
172 const bool useColorAsMask = (bool)element.attribute("ColorAsMask", "1").toInt();
173 brush.predefinedBrush.application = preserveLightness ? LIGHTNESSMAP : legacyBrushApplication(colorfulBrush, useColorAsMask);
174 }
175 else if (element.hasAttribute("brushApplication")) {
176 enumBrushApplication brushApplication = static_cast<enumBrushApplication>(KisDomUtils::toInt(element.attribute("brushApplication", "0")));
177 brush.predefinedBrush.application = brushApplication;
178 }
179 else if (element.hasAttribute("ColorAsMask")) {
180 KIS_SAFE_ASSERT_RECOVER_NOOP(colorfulBrush);
181
182 const bool useColorAsMask = (bool)element.attribute("ColorAsMask", "1").toInt();
183 brush.predefinedBrush.application =legacyBrushApplication(colorfulBrush, useColorAsMask);
184 }
185 else {
191 brush.predefinedBrush.application = legacyBrushApplication(colorfulBrush, false);
192 }
193
194 return {brush};
195}
bool hasColorAndTransparency() const
static void loadFromBrushResource(KisBrushModel::CommonData &commonData, KisBrushModel::PredefinedBrushData &predefinedBrushData, KisBrushSP brushResource)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
enumBrushApplication
Definition kis_brush.h:38
@ ALPHAMASK
Definition kis_brush.h:39
@ IMAGESTAMP
Definition kis_brush.h:40
@ LIGHTNESSMAP
Definition kis_brush.h:41
double toDouble(const QString &str, bool *ok=nullptr)
int toInt(const QString &str, bool *ok=nullptr)

References KisBrushModel::PredefinedBrushData::adjustmentMidPoint, ALPHAMASK, KisBrushModel::CommonData::angle, KisBrushModel::PredefinedBrushData::application, KisBrushModel::PredefinedBrushData::autoAdjustMidPoint, KisBrushModel::CommonData::autoSpacingCoeff, KisBrushModel::PredefinedBrushData::brightnessAdjustment, ResourceType::Brushes, KisBrushModel::BrushData::common, KisBrushModel::PredefinedBrushData::contrastAdjustment, KisBrushModel::PredefinedBrushData::hasColorAndTransparency, KisColorfulBrush::hasColorAndTransparency(), IMAGESTAMP, KIS_SAFE_ASSERT_RECOVER_NOOP, LIGHTNESSMAP, loadFromBrushResource(), KisBrushModel::Predefined, KisBrushModel::BrushData::predefinedBrush, KisBrushModel::PredefinedBrushData::scale, KisBrushModel::CommonData::spacing, KisDomUtils::toDouble(), KisDomUtils::toInt(), KisBrushModel::BrushData::type, and KisBrushModel::CommonData::useAutoSpacing.

◆ id()

QString KisPredefinedBrushFactory::id ( ) const
overridevirtual

Implements KisBrushFactory.

Definition at line 25 of file kis_predefined_brush_factory.cpp.

26{
27 return m_id;
28}

References m_id.

◆ loadFromBrushResource()

void KisPredefinedBrushFactory::loadFromBrushResource ( KisBrushModel::CommonData & commonData,
KisBrushModel::PredefinedBrushData & predefinedBrushData,
KisBrushSP brushResource )
static

Definition at line 197 of file kis_predefined_brush_factory.cpp.

198{
199 commonData.spacing = brushResource->spacing();
200 commonData.useAutoSpacing = brushResource->autoSpacingActive();
201 commonData.autoSpacingCoeff = brushResource->autoSpacingCoeff();
202 predefinedBrushData.resourceSignature = brushResource->signature();
203 predefinedBrushData.brushType = brushResource->brushType();
204 predefinedBrushData.baseSize = { brushResource->width(), brushResource->height() };
205
206 if (brushResource.dynamicCast<KisGbrBrush>()) {
207 predefinedBrushData.subtype = "gbr_brush";
208 } else if (brushResource.dynamicCast<KisAbrBrush>()) {
209 predefinedBrushData.subtype = "abr_brush";
210 } else if (brushResource.dynamicCast<KisPngBrush>()) {
211 predefinedBrushData.subtype = "png_brush";
212 } else if (brushResource.dynamicCast<KisSvgBrush>()) {
213 predefinedBrushData.subtype = "svg_brush";
214 } else {
215 KIS_SAFE_ASSERT_RECOVER_NOOP(0 && "unknown brush type");
216 }
217
218 KisImagePipeBrushSP imagepipeBrush = brushResource.dynamicCast<KisImagePipeBrush>();
219 if (imagepipeBrush) {
220 predefinedBrushData.parasiteSelection = imagepipeBrush->parasiteSelection();
221 }
222}

References KisBrushModel::CommonData::autoSpacingCoeff, KisBrushModel::PredefinedBrushData::baseSize, KisBrushModel::PredefinedBrushData::brushType, KIS_SAFE_ASSERT_RECOVER_NOOP, KisBrushModel::PredefinedBrushData::parasiteSelection, KisBrushModel::PredefinedBrushData::resourceSignature, KisBrushModel::CommonData::spacing, KisBrushModel::PredefinedBrushData::subtype, and KisBrushModel::CommonData::useAutoSpacing.

◆ toXML()

void KisPredefinedBrushFactory::toXML ( QDomDocument & doc,
QDomElement & element,
const KisBrushModel::BrushData & model )
overridevirtual

Implements KisBrushFactory.

Definition at line 224 of file kis_predefined_brush_factory.cpp.

225{
226 Q_UNUSED(doc);
227
228 e.setAttribute("type", id());
229 e.setAttribute("BrushVersion", "2");
230
231 e.setAttribute("filename", model.predefinedBrush.resourceSignature.filename);
232 e.setAttribute("md5sum", model.predefinedBrush.resourceSignature.md5sum);
233 e.setAttribute("spacing", QString::number(model.common.spacing));
234 e.setAttribute("useAutoSpacing", QString::number(model.common.useAutoSpacing));
235 e.setAttribute("autoSpacingCoeff", QString::number(model.common.autoSpacingCoeff));
236 e.setAttribute("angle", QString::number(model.common.angle));
237 e.setAttribute("scale", QString::number(model.predefinedBrush.scale));
238 e.setAttribute("brushApplication", QString::number((int)model.predefinedBrush.application));
239
240 if (id() == "abr_brush") {
241 e.setAttribute("name", model.predefinedBrush.resourceSignature.name);
242
243 } else {
244 // all other brushes are derived from KisColorfulBrush
245
246 // legacy setting, now 'brushApplication' is used instead
247 e.setAttribute("ColorAsMask", QString::number((int)(model.predefinedBrush.application != IMAGESTAMP)));
248
249 e.setAttribute("AdjustmentMidPoint", QString::number(model.predefinedBrush.adjustmentMidPoint));
250 e.setAttribute("BrightnessAdjustment", QString::number(model.predefinedBrush.brightnessAdjustment));
251 e.setAttribute("ContrastAdjustment", QString::number(model.predefinedBrush.contrastAdjustment));
252 e.setAttribute("AutoAdjustMidPoint", QString::number(model.predefinedBrush.autoAdjustMidPoint));
253 e.setAttribute("AdjustmentVersion", QString::number(2));
254 }
255}

References KisBrushModel::PredefinedBrushData::adjustmentMidPoint, KisBrushModel::CommonData::angle, KisBrushModel::PredefinedBrushData::application, KisBrushModel::PredefinedBrushData::autoAdjustMidPoint, KisBrushModel::CommonData::autoSpacingCoeff, KisBrushModel::PredefinedBrushData::brightnessAdjustment, KisBrushModel::BrushData::common, KisBrushModel::PredefinedBrushData::contrastAdjustment, KoResourceSignature::filename, IMAGESTAMP, KoResourceSignature::md5sum, KoResourceSignature::name, KisBrushModel::BrushData::predefinedBrush, KisBrushModel::PredefinedBrushData::resourceSignature, KisBrushModel::PredefinedBrushData::scale, KisBrushModel::CommonData::spacing, and KisBrushModel::CommonData::useAutoSpacing.

Member Data Documentation

◆ m_id

const QString KisPredefinedBrushFactory::m_id
private

Definition at line 34 of file kis_predefined_brush_factory.h.


The documentation for this class was generated from the following files: