Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_multichannel_utils.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Krita
3 *
4 * SPDX-FileCopyrightText: 2004 Cyrille Berger <cberger@cberger.net>
5 * SPDX-FileCopyrightText: 2021 Deif Lou <giniba@gmail.net>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include <KoColorSpace.h>
11#include <KoChannelInfo.h>
13#include <kis_assert.h>
15#include <kis_cubic_curve.h>
16
18
20
22
24 int maxChannels,
25 bool supportsLightness,
26 bool supportsHue,
27 bool supportsSaturation)
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}
93
94int findChannel(const QVector<VirtualChannelInfo> &virtualChannels,
95 const VirtualChannelInfo::Type &channelType)
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}
104
106 const QVector<QVector<quint16>> &transfers,
107 const QList<bool> &transferIsIdentity)
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}
265
266}
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
virtual KoColorTransformation * createBrightnessContrastAdjustment(const quint16 *transferValues) const =0
virtual KoColorTransformation * createPerChannelAdjustment(const quint16 *const *transferValues) const =0
QList< KoChannelInfo * > channels
virtual KoID colorModelId() 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
KoColorTransformation * 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.
QVector< VirtualChannelInfo > getVirtualChannels(const KoColorSpace *cs, int maxChannels, bool supportsLightness, bool supportsHue, bool supportsSaturation)
int findChannel(const QVector< VirtualChannelInfo > &virtualChannels, const VirtualChannelInfo::Type &channelType)
static KoColorTransformation * createOptimizedCompositeTransform(const QVector< KoColorTransformation * > transforms)