Krita Source Code Documentation
Loading...
Searching...
No Matches
KisMultiChannelUtils Namespace Reference

Functions

KoColorTransformationcreatePerChannelTransformationFromTransfers (const KoColorSpace *cs, const QVector< QVector< quint16 > > &transfers, const QList< bool > &transferIsIdentity)
 Create a composed per channel transformation object from the set of given transfers.
 
int findChannel (const QVector< VirtualChannelInfo > &virtualChannels, const VirtualChannelInfo::Type &channelType)
 
QVector< VirtualChannelInfogetVirtualChannels (const KoColorSpace *cs, int maxChannels, bool supportsLightness, bool supportsHue, bool supportsSaturation)
 

Function Documentation

◆ createPerChannelTransformationFromTransfers()

KoColorTransformation * KisMultiChannelUtils::createPerChannelTransformationFromTransfers ( const KoColorSpace * cs,
const QVector< QVector< quint16 > > & transfers,
const QList< bool > & transferIsIdentity )

Create a composed per channel transformation object from the set of given transfers.

Parameters
csa colorspace
transfersA collection of transfer luts
transferIsIdentityA collection of bools that indicate if the corresponding transfer has no effect (maps the input to itself)

TODO: What about the order of channels? (DK)

Virtual channels are sorted in display order, does Lcms accepts transforms in display order? Why on Earth it works?! Is it documented anywhere?

Sometimes the realTransfers are too low, this often happens with faulty config, which in turn leads to trouble when creating a transform.

createPerChannelAdjustment() expects alpha channel to be the last channel in the list, so just it here

createPerChannelAdjustment() expects alpha channel to be the last channel in the list, so just it here

Definition at line 105 of file kis_multichannel_utils.cpp.

108{
116 const QVector<VirtualChannelInfo> virtualChannels = getVirtualChannels(cs, transfers.size());
117
118 if (transfers.size() > int(virtualChannels.size())) {
119 // We got an illegal number of colorchannels :(
120 return 0;
121 }
122
123 bool colorsNull = true;
124 bool hueNull = true;
125 bool saturationNull = true;
126 bool lightnessNull = true;
127 bool allColorsNull = true;
128 int alphaIndexInReal = -1;
129
130 QVector<QVector<quint16> > realTransfers;
131 QVector<quint16> hueTransfer;
132 QVector<quint16> saturationTransfer;
133 QVector<quint16> lightnessTransfer;
134 QVector<quint16> allColorsTransfer;
135
136 for (int i = 0; i < virtualChannels.size(); i++) {
137 if (virtualChannels[i].type() == VirtualChannelInfo::REAL) {
138 realTransfers << transfers[i];
139
140 if (virtualChannels[i].isAlpha()) {
141 alphaIndexInReal = realTransfers.size() - 1;
142 }
143
144 if (colorsNull && !transferIsIdentity[i]) {
145 colorsNull = false;
146 }
147 } else if (virtualChannels[i].type() == VirtualChannelInfo::HUE) {
148 KIS_ASSERT_RECOVER_NOOP(hueTransfer.isEmpty());
149 hueTransfer = transfers[i];
150
151 if (hueNull && !transferIsIdentity[i]) {
152 hueNull = false;
153 }
154 } else if (virtualChannels[i].type() == VirtualChannelInfo::SATURATION) {
155 KIS_ASSERT_RECOVER_NOOP(saturationTransfer.isEmpty());
156 saturationTransfer = transfers[i];
157
158 if (saturationNull && !transferIsIdentity[i]) {
159 saturationNull = false;
160 }
161 } else if (virtualChannels[i].type() == VirtualChannelInfo::LIGHTNESS) {
162 KIS_ASSERT_RECOVER_NOOP(lightnessTransfer.isEmpty());
163 lightnessTransfer = transfers[i];
164
165 if (lightnessNull && !transferIsIdentity[i]) {
166 lightnessNull = false;
167 }
168 } else if (virtualChannels[i].type() == VirtualChannelInfo::ALL_COLORS) {
169 KIS_ASSERT_RECOVER_NOOP(allColorsTransfer.isEmpty());
170 allColorsTransfer = transfers[i];
171
172 if (allColorsNull && !transferIsIdentity[i]) {
173 allColorsNull = false;
174 }
175 }
176 }
177
178 KoColorTransformation *hueTransform = 0;
179 KoColorTransformation *saturationTransform = 0;
180 KoColorTransformation *lightnessTransform = 0;
181 KoColorTransformation *allColorsTransform = 0;
182 KoColorTransformation *colorTransform = 0;
183
188 int missingTransfers = qMax(0, int(cs->channelCount()-realTransfers.size()));
189 for (int i=0; i < missingTransfers; i++) {
190 realTransfers.append(KisCubicCurve().uint16Transfer());
191 }
192
193 if (!colorsNull) {
194 const quint16** transfers = new const quint16*[realTransfers.size()];
195 for(int i = 0; i < realTransfers.size(); ++i) {
196 transfers[i] = realTransfers[i].constData();
197
202 KIS_ASSERT_RECOVER_NOOP(i != alphaIndexInReal ||
203 alphaIndexInReal == (realTransfers.size() - 1));
204 }
205
206 colorTransform = cs->createPerChannelAdjustment(transfers);
207 delete [] transfers;
208 }
209
210 if (!hueNull) {
211 QHash<QString, QVariant> params;
212 params["curve"] = QVariant::fromValue(hueTransfer);
213 params["channel"] = KisHSVCurve::Hue;
214 params["relative"] = false;
215 params["lumaRed"] = cs->lumaCoefficients()[0];
216 params["lumaGreen"] = cs->lumaCoefficients()[1];
217 params["lumaBlue"] = cs->lumaCoefficients()[2];
218
219 hueTransform = cs->createColorTransformation("hsv_curve_adjustment", params);
220 }
221
222 if (!saturationNull) {
223 QHash<QString, QVariant> params;
224 params["curve"] = QVariant::fromValue(saturationTransfer);
225 params["channel"] = KisHSVCurve::Saturation;
226 params["relative"] = false;
227 params["lumaRed"] = cs->lumaCoefficients()[0];
228 params["lumaGreen"] = cs->lumaCoefficients()[1];
229 params["lumaBlue"] = cs->lumaCoefficients()[2];
230
231 saturationTransform = cs->createColorTransformation("hsv_curve_adjustment", params);
232 }
233
234 if (!lightnessNull) {
235 lightnessTransform = cs->createBrightnessContrastAdjustment(lightnessTransfer.constData());
236 }
237
238 if (!allColorsNull) {
239 const quint16** allColorsTransfers = new const quint16*[realTransfers.size()];
240 for(int i = 0; i < realTransfers.size(); ++i) {
241 allColorsTransfers[i] = (i != alphaIndexInReal) ?
242 allColorsTransfer.constData() : 0;
243
248 KIS_ASSERT_RECOVER_NOOP(i != alphaIndexInReal ||
249 alphaIndexInReal == (realTransfers.size() - 1));
250 }
251
252 allColorsTransform = cs->createPerChannelAdjustment(allColorsTransfers);
253 delete[] allColorsTransfers;
254 }
255
257 allTransforms << colorTransform;
258 allTransforms << allColorsTransform;
259 allTransforms << hueTransform;
260 allTransforms << saturationTransform;
261 allTransforms << lightnessTransform;
262
264}
virtual KoColorTransformation * createBrightnessContrastAdjustment(const quint16 *transferValues) const =0
virtual KoColorTransformation * createPerChannelAdjustment(const quint16 *const *transferValues) const =0
QVector< qreal > lumaCoefficients
virtual quint32 channelCount() const =0
KoColorTransformation * createColorTransformation(const QString &id, const QHash< QString, QVariant > &parameters) const
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
QVector< VirtualChannelInfo > getVirtualChannels(const KoColorSpace *cs, int maxChannels, bool supportsLightness, bool supportsHue, bool supportsSaturation)
static KoColorTransformation * createOptimizedCompositeTransform(const QVector< KoColorTransformation * > transforms)

References VirtualChannelInfo::ALL_COLORS, KoColorSpace::channelCount(), KoColorSpace::createBrightnessContrastAdjustment(), KoColorSpace::createColorTransformation(), KoCompositeColorTransformation::createOptimizedCompositeTransform(), KoColorSpace::createPerChannelAdjustment(), getVirtualChannels(), KisHSVCurve::Hue, VirtualChannelInfo::HUE, KIS_ASSERT_RECOVER_NOOP, VirtualChannelInfo::LIGHTNESS, KoColorSpace::lumaCoefficients, VirtualChannelInfo::REAL, KisHSVCurve::Saturation, and VirtualChannelInfo::SATURATION.

◆ findChannel()

int KisMultiChannelUtils::findChannel ( const QVector< VirtualChannelInfo > & virtualChannels,
const VirtualChannelInfo::Type & channelType )

Definition at line 94 of file kis_multichannel_utils.cpp.

96{
97 for (int i = 0; i < virtualChannels.size(); i++) {
98 if (virtualChannels[i].type() == channelType) {
99 return i;
100 }
101 }
102 return -1;
103}

◆ getVirtualChannels()

QVector< VirtualChannelInfo > KisMultiChannelUtils::getVirtualChannels ( const KoColorSpace * cs,
int maxChannels = -1,
bool supportsLightness = true,
bool supportsHue = true,
bool supportSaturation = true )

Get a list of adjustable channels for the color space. If maxChannels is non-negative, the number of channels is capped to the number. This is useful configurations from older documents (created in versions which supported fewer channels).

This is the extremely old version of the filter (< Krita 3.0). It has the following curves layout: R, G, B, A.

This is the old version of the filter (Krita [3.0, 5.0]). It has the following channel layout: RGBA, R, G, B, A, Lightness.

Starting Krita 5.1.0 Krita started to use the latest layout: RGBA, R, G, B, A, Hue, Saturation, Lightness

Definition at line 23 of file kis_multichannel_utils.cpp.

28{
29 supportsLightness =
30 supportsLightness &&
35
36 supportsHue = supportsHue && supportsLightness;
37 supportsSaturation = supportsSaturation && supportsLightness;
38
40
41 QList<KoChannelInfo *> sortedChannels =
43
44 if (maxChannels >= 0 && maxChannels == sortedChannels.size()) {
49 supportsLightness = false;
50 supportsHue = false;
51 supportsSaturation = false;
52 } else if (maxChannels >= 0 && maxChannels == sortedChannels.size() + 2) {
57 supportsHue = false;
58 supportsSaturation = false;
59 } else {
64 }
65
66 if (supportsLightness) {
68 }
69
70 Q_FOREACH (KoChannelInfo *channel, sortedChannels) {
72 vchannels << VirtualChannelInfo(VirtualChannelInfo::REAL, pixelIndex, channel, cs);
73 }
74
75 if (supportsHue) {
76 vchannels << VirtualChannelInfo(VirtualChannelInfo::HUE, -1, 0, cs);
77 }
78
79 if (supportsSaturation) {
81 }
82
83 if (supportsLightness) {
85 }
86
87 if (maxChannels >= 0 && vchannels.size() > maxChannels) {
88 vchannels.resize(maxChannels);
89 }
90
91 return vchannels;
92}
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID AlphaColorModelID("A", ki18n("Alpha mask"))
const KoID LABAColorModelID("LABA", ki18n("L*a*b*/Alpha"))
const KoID GrayColorModelID("GRAY", ki18n("Grayscale (without transparency)"))
static int displayPositionToChannelIndex(int displayPosition, const QList< KoChannelInfo * > &channels)
static QList< KoChannelInfo * > displayOrderSorted(const QList< KoChannelInfo * > &channels)
qint32 displayPosition() const
QList< KoChannelInfo * > channels
virtual KoID colorModelId() const =0

References VirtualChannelInfo::ALL_COLORS, AlphaColorModelID, KoColorSpace::channels, KoColorSpace::colorModelId(), KoChannelInfo::displayOrderSorted(), KoChannelInfo::displayPosition(), KoChannelInfo::displayPositionToChannelIndex(), GrayAColorModelID, GrayColorModelID, VirtualChannelInfo::HUE, LABAColorModelID, VirtualChannelInfo::LIGHTNESS, VirtualChannelInfo::REAL, and VirtualChannelInfo::SATURATION.