Krita Source Code Documentation
Loading...
Searching...
No Matches
KoLabColorSpaceTraits.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2007 Cyrille Berger <cberger@cberger.net>
3 * SPDX-FileCopyrightText: 2016, 2017, 2020 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
8#ifndef _KO_LAB_COLORSPACE_TRAITS_H_
9#define _KO_LAB_COLORSPACE_TRAITS_H_
10
12
26template<typename _channels_type_>
27struct KoLabTraits : public KoColorSpaceTrait<_channels_type_, 4, 3> {
28 typedef _channels_type_ channels_type;
31 static const qint32 L_pos = 0;
32 static const qint32 a_pos = 1;
33 static const qint32 b_pos = 2;
34
44
46 inline static channels_type L(quint8* data) {
48 return d[L_pos];
49 }
51 inline static void setL(quint8* data, channels_type nv) {
53 d[L_pos] = nv;
54 }
56 inline static channels_type a(quint8* data) {
58 return d[a_pos];
59 }
61 inline static void setA(quint8* data, channels_type nv) {
63 d[a_pos] = nv;
64 }
66 inline static channels_type b(quint8* data) {
68 return d[b_pos];
69 }
71 inline static void setB(quint8* data, channels_type nv) {
73 d[b_pos] = nv;
74 }
75
76 // Lab has some... particulars
77 inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex)
78 {
79 if (channelIndex > parent::channels_nb)
80 return QString("Error");
81 channels_type c = parent::nativeArray(pixel)[channelIndex];
82 switch (channelIndex) {
83 case L_pos:
84 return QString().setNum(100.0 * qBound((qreal)0, ((qreal)c) / math_trait::unitValueL, (qreal)math_trait::unitValueL));
85 case a_pos:
86 case b_pos:
87 if (c <= math_trait::halfValueAB) {
88 return QString().setNum(100.0 * (qreal)((c - math_trait::zeroValueAB) / (2.0 * (math_trait::halfValueAB - math_trait::zeroValueAB))));
89 } else {
90 return QString().setNum(100.0 * (qreal)(0.5 + (c - math_trait::halfValueAB) / (2.0 * (math_trait::unitValueAB - math_trait::halfValueAB))));
91 }
92 case 3:
93 return QString().setNum(100.0 * qBound((qreal)0, ((qreal)c) / math_trait::unitValue, (qreal)math_trait::unitValue));
94 default:
95 return QString("Error");
96 }
97 }
98 inline static void normalisedChannelsValue(const quint8 *pixel, QVector<float> &v)
99 {
100 Q_ASSERT((int)v.count() >= (int)parent::channels_nb);
102 float *channels = v.data();
103 for (uint i = 0; i < parent::channels_nb; i++) {
104 c = parent::nativeArray(pixel)[i];
105 switch (i) {
106 case L_pos:
107 channels[i] = (qreal)c / math_trait::unitValueL;
108 break;
109 case a_pos:
110 case b_pos:
111 if (c <= math_trait::halfValueAB) {
112 channels[i] = ((qreal)c - math_trait::zeroValueAB) / (2.0 * (math_trait::halfValueAB - math_trait::zeroValueAB));
113 } else {
114 channels[i] = 0.5 + ((qreal)c - math_trait::halfValueAB) / (2.0 * (math_trait::unitValueAB - math_trait::halfValueAB));
115 }
116 break;
117 // As per KoChannelInfo alpha channels are [0..1]
118 case 3:
119 default:
120 channels[i] = (qreal)c / math_trait::unitValue;
121 break;
122 }
123 }
124 }
125 inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector<float> &values)
126 {
127 Q_ASSERT((int)values.count() >= (int)parent::channels_nb);
129 for (uint i = 0; i < parent::channels_nb; i++) {
130 float b = 0;
131 switch (i) {
132 case L_pos:
133 b = qBound((float)math_trait::zeroValueL,
134 (float)math_trait::unitValueL * values[i],
135 (float)math_trait::unitValueL);
136 break;
137 case a_pos:
138 case b_pos:
139 if (values[i] <= 0.5) {
140 b = qBound((float)math_trait::zeroValueAB,
141 (float)(math_trait::zeroValueAB + 2.0 * values[i] * (math_trait::halfValueAB - math_trait::zeroValueAB)),
142 (float)math_trait::halfValueAB);
143 }
144 else {
145 b = qBound((float)math_trait::halfValueAB,
146 (float)(math_trait::halfValueAB + 2.0 * (values[i] - 0.5) * (math_trait::unitValueAB - math_trait::halfValueAB)),
147 (float)math_trait::unitValueAB);
148 }
149 break;
150 case 3:
151 b = qBound((float)math_trait::min,
152 (float)math_trait::unitValue * values[i],
153 (float)math_trait::unitValue);
154 default:
155 break;
156 }
157 c = (channels_type)b;
158 parent::nativeArray(pixel)[i] = c;
159 }
160 }
161};
162
163//For quint* values must range from 0 to 1 - see KoColorSpaceMaths<double, quint*>
164
165// https://github.com/mm2/Little-CMS/blob/master/src/cmspcs.c
166//PCS in Lab2 is encoded as:
167// 8 bit Lab PCS:
168// L* 0..100 into a 0..ff byte.
169// a* t + 128 range is -128.0 +127.0
170// b*
171// 16 bit Lab PCS:
172// L* 0..100 into a 0..ff00 word.
173// a* t + 128 range is -128.0 +127.9961
174// b*
175//Version 4
176//---------
177//CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffff
178//CIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff
179//CIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff
180
181struct KoLabU8Traits : public KoLabTraits<quint8> {
182
183};
184
185struct KoLabU16Traits : public KoLabTraits<quint16> {
186
187};
188
189// Float values are normalized to [0..100], [-128..+127], [-128..+127] - out of range values are clipped
190
191#include <KoConfig.h>
192#ifdef HAVE_OPENEXR
193#include <half.h>
194
195struct KoLabF16Traits : public KoLabTraits<half> {
196
197};
198
199#endif
200
201struct KoLabF32Traits : public KoLabTraits<float> {
202
203};
204
205struct KoLabF64Traits : public KoLabTraits<double> {
206
207};
208
209#endif
qreal v
unsigned int uint
static const quint32 channels_nb
the number of channels in this color space
static const channels_type * nativeArray(const quint8 *a)
static channels_type b(quint8 *data)
KoColorSpaceTrait< _channels_type_, 4, 3 > parent
static void fromNormalisedChannelsValue(quint8 *pixel, const QVector< float > &values)
static const qint32 a_pos
KoLabColorSpaceMathsTraits< channels_type > math_trait
_channels_type_ channels_type
static void setA(quint8 *data, channels_type nv)
Set the a component.
static void normalisedChannelsValue(const quint8 *pixel, QVector< float > &v)
static const qint32 L_pos
static void setL(quint8 *data, channels_type nv)
Set the L component.
static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex)
static channels_type L(quint8 *data)
static channels_type a(quint8 *data)
static const qint32 b_pos
static void setB(quint8 *data, channels_type nv)
Set the a component.