Krita Source Code Documentation
Loading...
Searching...
No Matches
LabColorSpace.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006 Cyrille Berger <cberger@cberger.net>
3 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 */
7
8#include "LabColorSpace.h"
9
10#include <QDomElement>
11
12#include <klocalizedstring.h>
13
14#include "../compositeops/KoCompositeOps.h"
16#include <KoColorConversions.h>
17#include <kis_dom_utils.h>
18
20 : LcmsColorSpace<KoLabU16Traits>(colorSpaceId(), name, TYPE_LABA_16, cmsSigLabData, p)
21{
22 addChannel(new KoChannelInfo(i18nc("Lightness value in Lab color model", "Lightness"), 0 * sizeof(quint16), 0, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(100, 100, 100)));
23 addChannel(new KoChannelInfo(i18n("a*"), 1 * sizeof(quint16), 1, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(150, 150, 150)));
24 addChannel(new KoChannelInfo(i18n("b*"), 2 * sizeof(quint16), 2, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(200, 200, 200)));
25 addChannel(new KoChannelInfo(i18n("Alpha"), 3 * sizeof(quint16), 3, KoChannelInfo::ALPHA, KoChannelInfo::UINT16, sizeof(quint16)));
26
27 init();
28
29 addStandardCompositeOps<KoLabU16Traits>(this);
30 addStandardDitherOps<KoLabU16Traits>(this);
31}
32
34{
35 if (independence == TO_RGBA8) {
36 return true;
37 } else {
38 return false;
39 }
40}
41
43{
44 return new LabU16ColorSpace(name(), profile()->clone());
45}
46
47void LabU16ColorSpace::colorToXML(const quint8 *pixel, QDomDocument &doc, QDomElement &colorElt) const
48{
49 const KoLabU16Traits::Pixel *p = reinterpret_cast<const KoLabU16Traits::Pixel *>(pixel);
50 QDomElement labElt = doc.createElement("Lab");
51
52 qreal a, b;
54
55 if (p->a <= halfValue) {
56 a = double(double(halfValue - p->a) / halfValue);
57 a = a * -128.0;
58 } else {
59 a = double(double(p->a - halfValue) / halfValue);
60 a = 127.0 * a;
61 }
62
63 if (p->b <= halfValue) {
64 b = double(double(halfValue - p->b) / halfValue);
65 b = b * -128.0;
66 } else {
67 b = double(double(p->b - halfValue) / halfValue);
68 b = 127.0 * b;
69 }
70
72 labElt.setAttribute("a", KisDomUtils::toString(a));
73 labElt.setAttribute("b", KisDomUtils::toString(b));
74 labElt.setAttribute("space", profile()->name());
75 colorElt.appendChild(labElt);
76}
77
78void LabU16ColorSpace::colorFromXML(quint8 *pixel, const QDomElement &elt) const
79{
80 KoLabU16Traits::Pixel *p = reinterpret_cast<KoLabU16Traits::Pixel *>(pixel);
81
82 double a = KisDomUtils::toDouble(elt.attribute("a"));
83 double b = KisDomUtils::toDouble(elt.attribute("b"));
84
85 // L will go from 0 to 100
86
89
90 // a goes from -128 to 127
91 if(a <= 0) {
92 a = (a/-128.0);
93 p->a = halfValue - (a * halfValue);
94 } else {
95 a = fabs(a/127.0);
96 p->a = (a * halfValue) + halfValue;
97 }
98
99 if(b <= 0) {
100 b = (b/-128.0);
101 p->b = halfValue - (b * halfValue);
102 } else {
103 b = fabs(b/127.0);
104 p->b = (b * halfValue) + halfValue;
105 }
106
108}
109void LabU16ColorSpace::toHSY(const QVector<double> &channelValues, qreal *hue, qreal *sat, qreal *luma) const
110{
111 LabToLCH(channelValues[0],channelValues[1],channelValues[2], luma, sat, hue);
112}
113
114QVector <double> LabU16ColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const
115{
116 QVector <double> channelValues(4);
117 LCHToLab(*luma, *sat, *hue, &channelValues[0],&channelValues[1],&channelValues[2]);
118 channelValues[3]=1.0;
119 return channelValues;
120}
121
122void LabU16ColorSpace::toYUV(const QVector<double> &channelValues, qreal *y, qreal *u, qreal *v) const
123{
124 *y =channelValues[0];
125 *u=channelValues[1];
126 *v=channelValues[2];
127}
128
129QVector <double> LabU16ColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const
130{
131 QVector <double> channelValues(4);
132 channelValues[0]=*y;
133 channelValues[1]=*u;
134 channelValues[2]=*v;
135 channelValues[3]=1.0;
136 return channelValues;
137}
138
139quint8 LabU16ColorSpace::scaleToU8(const quint8 *srcPixel, qint32 channelIndex) const
140{
141 typename ColorSpaceTraits::channels_type c = ColorSpaceTraits::nativeArray(srcPixel)[channelIndex];
142 qreal b = 0;
143 switch (channelIndex) {
144 case ColorSpaceTraits::L_pos:
145 b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValueL;
146 break;
147 case ColorSpaceTraits::a_pos:
148 case ColorSpaceTraits::b_pos:
149 if (c <= ColorSpaceTraits::math_trait::halfValueAB) {
150 b = ((qreal)c - ColorSpaceTraits::math_trait::zeroValueAB) / (2.0 * (ColorSpaceTraits::math_trait::halfValueAB - ColorSpaceTraits::math_trait::zeroValueAB));
151 } else {
152 b = 0.5 + ((qreal)c - ColorSpaceTraits::math_trait::halfValueAB) / (2.0 * (ColorSpaceTraits::math_trait::unitValueAB - ColorSpaceTraits::math_trait::halfValueAB));
153 }
154 break;
155 default:
156 b = ((qreal)c) / ColorSpaceTraits::math_trait::unitValue;
157 break;
158 }
159
161}
162
163void LabU16ColorSpace::convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const qint32 selectedChannelIndex) const
164{
165 for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) {
166 for (uint channelIndex = 0; channelIndex < ColorSpaceTraits::channels_nb; ++channelIndex) {
167 if (channelIndex != ColorSpaceTraits::alpha_pos) {
168 if (channelIndex == ColorSpaceTraits::L_pos) {
169 ColorSpaceTraits::channels_type c = ColorSpaceTraits::nativeArray((src + (pixelIndex * ColorSpaceTraits::pixelSize)))[selectedChannelIndex];
170 switch (selectedChannelIndex) {
171 case ColorSpaceTraits::L_pos:
172 break;
173 case ColorSpaceTraits::a_pos:
174 case ColorSpaceTraits::b_pos:
175 if (c <= ColorSpaceTraits::math_trait::halfValueAB) {
176 c = ColorSpaceTraits::math_trait::unitValueL * (((qreal)c - ColorSpaceTraits::math_trait::zeroValueAB) / (2.0 * (ColorSpaceTraits::math_trait::halfValueAB - ColorSpaceTraits::math_trait::zeroValueAB)));
177 } else {
178 c = ColorSpaceTraits::math_trait::unitValueL * (0.5 + ((qreal)c - ColorSpaceTraits::math_trait::halfValueAB) / (2.0 * (ColorSpaceTraits::math_trait::unitValueAB - ColorSpaceTraits::math_trait::halfValueAB)));
179 }
180 break;
181 // As per KoChannelInfo alpha channels are [0..1]
182 default:
183 c = ColorSpaceTraits::math_trait::unitValueL * (qreal)c / ColorSpaceTraits::math_trait::unitValue;
184 break;
185 }
186 ColorSpaceTraits::nativeArray(dst + (pixelIndex * ColorSpaceTraits::pixelSize))[channelIndex] = c;
187 } else {
188 ColorSpaceTraits::nativeArray(dst + (pixelIndex * ColorSpaceTraits::pixelSize))[channelIndex] = ColorSpaceTraits::math_trait::halfValueAB;
189 }
190 } else {
191 ColorSpaceTraits::nativeArray((dst + (pixelIndex * ColorSpaceTraits::pixelSize)))[channelIndex] =
192 ColorSpaceTraits::nativeArray((src + (pixelIndex * ColorSpaceTraits::pixelSize)))[channelIndex];
193 }
194 }
195 }
196}
197
198void LabU16ColorSpace::convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const QBitArray selectedChannels) const
199{
200 for (uint pixelIndex = 0; pixelIndex < nPixels; ++pixelIndex) {
201 for (uint channelIndex = 0; channelIndex < ColorSpaceTraits::channels_nb; ++channelIndex) {
202 if (selectedChannels.testBit(channelIndex)) {
203 ColorSpaceTraits::nativeArray((dst + (pixelIndex * ColorSpaceTraits::pixelSize)))[channelIndex] =
204 ColorSpaceTraits::nativeArray((src + (pixelIndex * ColorSpaceTraits::pixelSize)))[channelIndex];
205 } else {
206 ColorSpaceTraits::channels_type v;
207 switch (channelIndex) {
208 case ColorSpaceTraits::L_pos:
209 v = ColorSpaceTraits::math_trait::halfValueL;
210 break;
211 case ColorSpaceTraits::a_pos:
212 case ColorSpaceTraits::b_pos:
213 v = ColorSpaceTraits::math_trait::halfValueAB;
214 break;
215 default:
216 v = ColorSpaceTraits::math_trait::zeroValue;
217 break;
218 }
219 ColorSpaceTraits::nativeArray((dst + (pixelIndex * ColorSpaceTraits::pixelSize)))[channelIndex] = v;
220 }
221 }
222 }
223}
const Params2D p
qreal v
qreal u
void LabToLCH(const qreal l, const qreal a, const qreal b, qreal *L, qreal *C, qreal *H)
void LCHToLab(const qreal L, const qreal C, const qreal H, qreal *l, qreal *a, qreal *b)
ColorSpaceIndependence
@ TO_RGBA8
unsigned int uint
#define TYPE_LABA_16
@ ALPHA
The channel represents the opacity of a pixel.
@ COLOR
The channel represents a color.
@ UINT16
use this for an integer 16bits channel
static _Tdst scaleToA(_T a)
virtual void addChannel(KoChannelInfo *ci)
void colorFromXML(quint8 *pixel, const QDomElement &elt) const override
quint8 scaleToU8(const quint8 *srcPixel, qint32 channelIndex) const override
bool willDegrade(ColorSpaceIndependence independence) const override
void convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const qint32 selectedChannelIndex) const override
virtual KoColorSpace * clone() const
void colorToXML(const quint8 *pixel, QDomDocument &doc, QDomElement &colorElt) const override
QVector< double > fromYUV(qreal *y, qreal *u, qreal *v) const override
void toHSY(const QVector< double > &channelValues, qreal *hue, qreal *sat, qreal *luma) const override
void toYUV(const QVector< double > &channelValues, qreal *y, qreal *u, qreal *v) const override
QVector< double > fromHSY(qreal *hue, qreal *sat, qreal *luma) const override
LabU16ColorSpace(const QString &name, KoColorProfile *p)
const KoColorProfile * profile() const override
double toDouble(const QString &str, bool *ok=nullptr)
QString toString(const QString &value)
_channels_type_ channels_type
the type of the value of the channels of this color space