Krita Source Code Documentation
Loading...
Searching...
No Matches
KisLevelsFilterConfiguration.cpp
Go to the documentation of this file.
1/*
2 * KDE. Krita Project.
3 *
4 * SPDX-FileCopyrightText: 2021 Deif Lou <ginoba@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include <QRegularExpression>
10
11#include <kis_dom_utils.h>
12
14
16 : KisColorTransformationConfiguration(defaultName(), version, resourcesInterface)
17{
20
21}
22
24 : KisLevelsFilterConfiguration(channelCount, defaultVersion(), resourcesInterface)
25{}
26
29 , m_transfers(rhs.m_transfers)
30 , m_lightnessTransfer(rhs.m_lightnessTransfer)
31{}
32
37
42
44{
45 QVector<KisLevelsCurve> levelsCurves_;
46 for (qint32 i = 0; i < channelCount(); ++i) {
47 const QString levelsCurveStr = getString(QString("channel_") + KisDomUtils::toString(i), "");
48 levelsCurves_.append(levelsCurveStr.isEmpty() ? KisLevelsCurve() : KisLevelsCurve(levelsCurveStr));
49 }
50 return levelsCurves_;
51}
52
54{
55 const QString levelsCurveStr = getString("lightness", "");
56 return levelsCurveStr.isEmpty() ? KisLevelsCurve() : KisLevelsCurve(levelsCurveStr);
57}
58
60{
61 for (int i = 0; i < newLevelsCurves.size(); ++i) {
62 setProperty(QString("channel_") + KisDomUtils::toString(i), newLevelsCurves[i].toString());
63 }
64 setChannelCount(newLevelsCurves.size());
66}
67
69{
70 setProperty("lightness", newLightnessLevelsCurve.toString());
71}
72
74{
76 m_transfers.resize(lc.size());
77 for (int i = 0; i < lc.size(); i++) {
78 m_transfers[i] = lc[i].uint16Transfer();
79 }
80}
81
83{
84 const KisLevelsCurve lightnessLevelsCurve_ = lightnessLevelsCurve();
85
86 m_lightnessTransfer = lightnessLevelsCurve_.uint16Transfer();
87}
88
93
98
100{
101 const QString mode = getString("mode", "");
102 if (mode == "lightness") {
103 return true;
104 } else if (mode == "channels") {
105 return false;
106 }
108}
109
111{
112 const QString mode = getString("histogram_mode", "");
113 if (mode == "logarithmic") {
114 return true;
115 } else if (mode == "linear") {
116 return false;
117 }
119}
120
122{
123 setProperty("mode", newUseLightnessMode ? "lightness" : "channels");
124}
125
127{
128 setProperty("histogram_mode", newShowLogarithmicHistogram ? "logarithmic" : "linear");
129}
130
141{
142 const double inputBlackPoint = static_cast<double>(getInt("blackvalue", 0)) / 255.0;
143 const double inputWhitePoint = static_cast<double>(getInt("whitevalue", 255)) / 255.0;
144 const double inputGamma = getDouble("gammavalue", 1.0);
145 const double outputBlackPoint = static_cast<double>(getInt("outblackvalue", 0)) / 255.0;
146 const double outputWhitePoint = static_cast<double>(getInt("outwhitevalue", 255)) / 255.0;
148 "lightness",
149 KisLevelsCurve(inputBlackPoint, inputWhitePoint, inputGamma, outputBlackPoint, outputWhitePoint).toString()
150 );
151}
152
164{
165 KisLevelsCurve lightnessLevelsCurve_ = lightnessLevelsCurve();
166 KisColorTransformationConfiguration::setProperty("blackvalue", static_cast<int>(qRound(lightnessLevelsCurve_.inputBlackPoint() * 255.0)));
167 KisColorTransformationConfiguration::setProperty("whitevalue", static_cast<int>(qRound(lightnessLevelsCurve_.inputWhitePoint() * 255.0)));
168 KisColorTransformationConfiguration::setProperty("gammavalue", lightnessLevelsCurve_.inputGamma());
169 KisColorTransformationConfiguration::setProperty("outblackvalue", static_cast<int>(qRound(lightnessLevelsCurve_.outputBlackPoint() * 255.0)));
170 KisColorTransformationConfiguration::setProperty("outwhitevalue", static_cast<int>(qRound(lightnessLevelsCurve_.outputWhitePoint() * 255.0)));
171}
172
182void KisLevelsFilterConfiguration::setProperty(const QString &name, const QVariant &value)
183{
185
186 if (name == "lightness") {
189 } else if (name == "blackvalue" || name == "whitevalue" || name == "gammavalue" ||
190 name == "outblackvalue" || name == "outwhitevalue") {
193 } else if (QRegularExpression("channel_\\d+").match(name).hasMatch()) {
195 }
196}
197
199{
200 return getInt("number_of_channels", 0);
201}
202
204{
205 setProperty("number_of_channels", newChannelCount);
206}
207
209{
210 fromXML(root);
211}
212
213void KisLevelsFilterConfiguration::fromXML(const QDomElement& root)
214{
215 int version;
216 version = root.attribute("version").toInt();
217
218 QDomElement e = root.firstChild().toElement();
219 QString attributeName;
222 bool lightnessMode = defaultUseLightnessMode();
223 bool logarithmicHistogram = defaultShowLogarithmicHistogram();
224
225 if (version == 1) {
226 while (!e.isNull()) {
227 attributeName = e.attribute("name");
228 if (attributeName == "gammavalue") {
229 const double value = KisDomUtils::toDouble(e.text());
231 } else {
232 const double value = KisDomUtils::toDouble(e.text()) / 255.0;
233 if (attributeName == "blackvalue") {
235 } else if (attributeName == "whitevalue") {
237 } else if (attributeName == "outblackvalue") {
239 } else if (attributeName == "outwhitevalue") {
241 }
242 }
243 e = e.nextSiblingElement();
244 }
245 } else if (version == 2) {
246 int numChannels = 0;
247 QHash<int, KisLevelsCurve> unsortedLevelsCurves;
248 KisLevelsCurve levelsCurve;
249
250 while (!e.isNull()) {
251 attributeName = e.attribute("name");
252 if (attributeName == "mode") {
253 lightnessMode = e.text() != "channels";
254 } else if (attributeName == "histogram_mode") {
255 logarithmicHistogram = e.text() == "logarithmic";
256 } else if (attributeName == "lightness") {
258 } else if (attributeName == "number_of_channels") {
259 numChannels = e.text().toInt();
260 } else {
261 const QRegularExpression rx("channel_(\\d+)");
262 const QRegularExpressionMatch match = rx.match(attributeName);
263 if (match.hasMatch()) {
264 const int index = match.captured(1).toInt();
265 if (!e.text().isEmpty()) {
266 levelsCurve.fromString(e.text());
267 unsortedLevelsCurves[index] = levelsCurve;
268 }
269 }
270 }
271 e = e.nextSiblingElement();
272 }
273
274 for (int i = 0; i < numChannels; ++i) {
275 if (unsortedLevelsCurves.contains(i)) {
276 levelsCurves.append(unsortedLevelsCurves[i]);
277 } else {
279 }
280 }
281 }
282
286 setUseLightnessMode(lightnessMode);
287 setShowLogarithmicHistogram(logarithmicHistogram);
288}
289
290void addParamNode(QDomDocument& doc,
291 QDomElement& root,
292 const QString &name,
293 const QString &value,
294 bool internal = false)
295{
296 QDomText text = doc.createTextNode(value);
297 QDomElement t = doc.createElement("param");
298 t.setAttribute("name", name);
299 if (internal) {
300 t.setAttribute("type", "internal");
301 }
302 t.appendChild(text);
303 root.appendChild(t);
304}
305
306void KisLevelsFilterConfiguration::toXML(QDomDocument& doc, QDomElement& root) const
307{
334 root.setAttribute("version", version());
335
336 QDomText text;
337 QDomElement t;
338
339 addParamNode(doc, root, "mode", useLightnessMode() ? "lightness" : "channels");
340 addParamNode(doc, root, "histogram_mode", showLogarithmicHistogram() ? "logarithmic" : "linear");
341 addParamNode(doc, root, "lightness", lightnessLevelsCurve().toString());
342 addParamNode(doc, root, "number_of_channels", KisDomUtils::toString(channelCount()));
343
344 const QVector<KisLevelsCurve> levelsCurves_ = levelsCurves();
345 for (int i = 0; i < levelsCurves_.size(); ++i) {
346 const QString name = QString("channel_") + KisDomUtils::toString(i);
347 const QString value = levelsCurves_[i].toString();
348 addParamNode(doc, root, name, value);
349 }
350 const KisLevelsCurve lightnessCurve_ = lightnessLevelsCurve();
351 addParamNode(doc, root, "blackvalue", KisDomUtils::toString(static_cast<int>(qRound(lightnessCurve_.inputBlackPoint() * 255.0))), true);
352 addParamNode(doc, root, "whitevalue", KisDomUtils::toString(static_cast<int>(qRound(lightnessCurve_.inputWhitePoint() * 255.0))), true);
353 addParamNode(doc, root, "gammavalue", KisDomUtils::toString(lightnessCurve_.inputGamma()), true);
354 addParamNode(doc, root, "outblackvalue", KisDomUtils::toString(static_cast<int>(qRound(lightnessCurve_.outputBlackPoint() * 255.0))), true);
355 addParamNode(doc, root, "outwhitevalue", KisDomUtils::toString(static_cast<int>(qRound(lightnessCurve_.outputWhitePoint() * 255.0))), true);
356}
357
float value(const T *src, size_t ch)
void addParamNode(QDomDocument &doc, QDomElement &root, const QString &name, const QString &value, bool internal=false)
This class holds the parameters for a levels adjustment. It is modeled after KisCubicCurve and has si...
qreal outputBlackPoint() const
Get the output black point.
void setOutputBlackPoint(qreal newOutputBlackPoint)
Set the output black point.
qreal inputBlackPoint() const
Get the input black point.
void setOutputWhitePoint(qreal newOutputWhitePoint)
Set the output white point.
qreal inputGamma() const
Get the gamma value.
const QVector< quint16 > & uint16Transfer(int size=256) const
Returns a vector of size.
qreal inputWhitePoint() const
Get the input white point.
void setInputGamma(qreal newInputGamma)
Set the gamma value.
void setInputWhitePoint(qreal newInputWhitePoint)
Set the input white point.
QString toString() const
Get a text representation of the parameters. The format is: "input_black_point;input_white_point;inpu...
void fromString(const QString &text, bool *ok=nullptr)
Parses the parameters from a given text.
qreal outputWhitePoint() const
Get the output white point.
void setInputBlackPoint(qreal newInputBlackPoint)
Set the input black point.
void setLevelsCurves(const QVector< KisLevelsCurve > &newLevelsCurves)
const KisLevelsCurve lightnessLevelsCurve() const
QVector< QVector< quint16 > > m_transfers
KisFilterConfigurationSP clone() const override
void setProperty(const QString &name, const QVariant &value) override
void fromLegacyXML(const QDomElement &root) override
static constexpr bool defaultShowLogarithmicHistogram()
void setShowLogarithmicHistogram(bool newShowLogarithmicHistogram)
static constexpr bool defaultUseLightnessMode()
const QVector< KisLevelsCurve > levelsCurves() const
void setUseLightnessMode(bool newUseLightnessMode)
void setLightnessLevelsCurve(const KisLevelsCurve &newLightnessLevelsCurve)
const QVector< QVector< quint16 > > & transfers() const
const QVector< quint16 > & lightnessTransfer() const
bool isCompatible(const KisPaintDeviceSP) const override
void fromXML(const QDomElement &e) override
KisLevelsFilterConfiguration(int channelCount, qint32 version, KisResourcesInterfaceSP resourcesInterface)
virtual const KoColorSpace * compositionSourceColorSpace() const
virtual quint32 channelCount() const =0
void addParamNode(QDomDocument &doc, QDomElement &root, const QString &name, const QString &value)
double toDouble(const QString &str, bool *ok=nullptr)
QString toString(const QString &value)
void setProperty(const QString &name, const QVariant &value) override
QString getString(const QString &name, const QString &def=QString()) const
int getInt(const QString &name, int def=0) const
double getDouble(const QString &name, double def=0.0) const