Krita Source Code Documentation
Loading...
Searching...
No Matches
KoLabColorSpaceMaths.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006, 2007, 2010 Cyrille Berger <cberger@cberger.net>
3 * SPDX-FileCopyrightText: 2017, 2020 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
8#ifndef KOLABCOLORSPACEMATHS_H_
9#define KOLABCOLORSPACEMATHS_H_
10
11#include <cmath>
12#include <limits>
13
14#include "kritapigment_export.h"
15#include <KoIntegerMaths.h>
16#include "KoChannelInfo.h"
17#include "KoLut.h"
18
19#include <KoColorSpaceMaths.h>
20
21#undef _T
22
42template<typename _T>
44{
45public:
46};
47
48template<>
49class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<quint8> : public KoColorSpaceMathsTraits<quint8>
50{
51public:
52 static const quint8 zeroValueL = 0;
53 static const quint8 unitValueL = 0x00FF;
54 static const quint8 halfValueL = 0x00FF / 2;
55 static const quint8 zeroValueAB = 0;
56 static const quint8 unitValueAB = 0x00FF;
57 static const quint8 halfValueAB = 0x0080;
58};
59
60template<>
61class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<quint16> : public KoColorSpaceMathsTraits<quint16>
62{
63public:
64 static const quint16 zeroValueL = 0;
65 static const quint16 unitValueL = 0xFFFF;
66 static const quint16 halfValueL = 0xFFFF / 2;
67 static const quint16 zeroValueAB = 0;
68 static const quint16 unitValueAB = 0xFFFF;
69 static const quint16 halfValueAB = 0x8080;
70};
71
72template<>
73class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<qint16> : public KoColorSpaceMathsTraits<qint16>
74{
75public:
76 static const qint16 zeroValueL = 0;
77 static const qint16 unitValueL = 32767;
78 static const qint16 halfValueL = 32767 / 2;
79 static const qint16 zeroValueAB = 0;
80 static const qint16 unitValueAB = 32767;
81 static const qint16 halfValueAB = 19549;
82};
83
84template<>
85class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<quint32> : public KoColorSpaceMathsTraits<quint32>
86{
87public:
88 static const quint32 zeroValueL = 0;
89 static const quint32 unitValueL = 0xFFFFFFFF;
90 static const quint32 halfValueL = 0xFFFFFFFF / 2;
91 static const quint32 zeroValueAB = 0;
92 static const quint32 unitValueAB = 0xFFFFFFFF;
93 static const quint32 halfValueAB = 0x80808080;
94};
95
96#include <KoConfig.h>
97#ifdef HAVE_OPENEXR
98#include <half.h>
99
100template<>
101class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<half> : public KoColorSpaceMathsTraits<half>
102{
103public:
104 static const half zeroValueL;
105 static const half unitValueL;
106 static const half halfValueL;
107 static const half zeroValueAB;
108 static const half unitValueAB;
109 static const half halfValueAB;
110};
111#endif
112
113template<>
114class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<float> : public KoColorSpaceMathsTraits<float>
115{
116public:
117 static const float zeroValueL;
118 static const float unitValueL;
119 static const float halfValueL;
120 static const float zeroValueAB;
121 static const float unitValueAB;
122 static const float halfValueAB;
123};
124
125template<>
126class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits<double> : public KoColorSpaceMathsTraits<double>
127{
128public:
129 static const double zeroValueL;
130 static const double unitValueL;
131 static const double halfValueL;
132 static const double zeroValueAB;
133 static const double unitValueAB;
134 static const double halfValueAB;
135};
136
137//template<typename _T_>
138//struct KoIntegerToFloat {
139// inline float operator()(_T_ f) const
140// {
141// return f / float(KoColorSpaceMathsTraits<_T_>::max);
142// }
143//};
144
145//struct KoLuts {
146
147// static KRITAPIGMENT_EXPORT const Ko::FullLut< KoIntegerToFloat<quint16>, float, quint16> Uint16ToFloat;
148// static KRITAPIGMENT_EXPORT const Ko::FullLut< KoIntegerToFloat<quint8>, float, quint8> Uint8ToFloat;
149//};
150
152// * This class defines some elementary operations used by various color
153// * space. It's intended to be generic, but some specialization exists
154// * either for optimization or just for being buildable.
155// *
156// * @param _T some numerical type with an existing trait
157// * @param _Tdst some other numerical type with an existing trait, it is
158// * only needed if different of _T
159// */
160//template < typename _T, typename _Tdst = _T >
161//class KoColorSpaceMaths
162//{
163// typedef KoColorSpaceMathsTraits<_T> traits;
164// typedef typename traits::compositetype src_compositetype;
165// typedef typename KoColorSpaceMathsTraits<_Tdst>::compositetype dst_compositetype;
166
167//public:
168// inline static _Tdst multiply(_T a, _Tdst b) {
169// return (dst_compositetype(a)*b) / KoColorSpaceMathsTraits<_Tdst>::unitValue;
170// }
171
172// inline static _Tdst multiply(_T a, _Tdst b, _Tdst c) {
173// return (dst_compositetype(a)*b*c) / (dst_compositetype(KoColorSpaceMathsTraits<_Tdst>::unitValue) * KoColorSpaceMathsTraits<_T>::unitValue);
174// }
175
176// /**
177// * Division : (a * MAX ) / b
178// * @param a
179// * @param b
180// */
181// inline static dst_compositetype divide(_T a, _Tdst b) {
182// return (dst_compositetype(a) * KoColorSpaceMathsTraits<_Tdst>::unitValue) / b;
183// }
184
185// /**
186// * Inversion : unitValue - a
187// * @param a
188// */
189// inline static _T invert(_T a) {
190// return traits::unitValue - a;
191// }
192
193// /**
194// * Blending : (a * alpha) + b * (1 - alpha)
195// * @param a
196// * @param b
197// * @param alpha
198// */
199// inline static _T blend(_T a, _T b, _T alpha) {
200// src_compositetype c = ((src_compositetype(a) - b) * alpha) / traits::unitValue;
201// return c + b;
202// }
203
204// /**
205// * This function will scale a value of type _T to fit into a _Tdst.
206// */
207// inline static _Tdst scaleToA(_T a) {
208// return _Tdst(dst_compositetype(a) * KoColorSpaceMathsTraits<_Tdst>::unitValue / KoColorSpaceMathsTraits<_T>::unitValue);
209// }
210
211// inline static dst_compositetype clamp(dst_compositetype val) {
212// return qBound<dst_compositetype>(KoColorSpaceMathsTraits<_Tdst>::min, val, KoColorSpaceMathsTraits<_Tdst>::max);
213// }
214
215// /**
216// * Clamps the composite type on higher border only. That is a fast path
217// * for scale-only transformations
218// */
219// inline static _Tdst clampAfterScale(dst_compositetype val) {
220// return qMin<dst_compositetype>(val, KoColorSpaceMathsTraits<_Tdst>::max);
221// }
222//};
223
225//template<>
226//inline quint8 KoColorSpaceMaths<double, quint8>::scaleToA(double a)
227//{
228// double v = a * 255;
229// return float2int(CLAMP(v, 0, 255));
230//}
231
232//template<>
233//inline double KoColorSpaceMaths<quint8, double>::scaleToA(quint8 a)
234//{
235// return KoLuts::Uint8ToFloat(a);
236//}
237
238//template<>
239//inline quint16 KoColorSpaceMaths<double, quint16>::scaleToA(double a)
240//{
241// double v = a * 0xFFFF;
242// return float2int(CLAMP(v, 0, 0xFFFF));
243//}
244
245//template<>
246//inline double KoColorSpaceMaths<quint16, double>::scaleToA(quint16 a)
247//{
248// return KoLuts::Uint16ToFloat(a);
249//}
250
251//template<>
252//inline double KoColorSpaceMaths<double>::clamp(double a)
253//{
254// return a;
255//}
256
258
259//template<>
260//inline float KoColorSpaceMaths<double, float>::scaleToA(double a)
261//{
262// return (float)a;
263//}
264
265//template<>
266//inline double KoColorSpaceMaths<float, double>::scaleToA(float a)
267//{
268// return a;
269//}
270
271//template<>
272//inline quint16 KoColorSpaceMaths<float, quint16>::scaleToA(float a)
273//{
274// float v = a * 0xFFFF;
275// return (quint16)float2int(CLAMP(v, 0, 0xFFFF));
276//}
277
278//template<>
279//inline float KoColorSpaceMaths<quint16, float>::scaleToA(quint16 a)
280//{
281// return KoLuts::Uint16ToFloat(a);
282//}
283
284//template<>
285//inline quint8 KoColorSpaceMaths<float, quint8>::scaleToA(float a)
286//{
287// float v = a * 255;
288// return (quint8)float2int(CLAMP(v, 0, 255));
289//}
290
291//template<>
292//inline float KoColorSpaceMaths<quint8, float>::scaleToA(quint8 a)
293//{
294// return KoLuts::Uint8ToFloat(a);
295//}
296
297//template<>
298//inline float KoColorSpaceMaths<float>::blend(float a, float b, float alpha)
299//{
300// return (a - b) * alpha + b;
301//}
302
303//template<>
304//inline double KoColorSpaceMaths<float>::clamp(double a)
305//{
306// return a;
307//}
308
310
311//#ifdef HAVE_OPENEXR
312
313//template<>
314//inline half KoColorSpaceMaths<double, half>::scaleToA(double a)
315//{
316// return (half)a;
317//}
318
319//template<>
320//inline double KoColorSpaceMaths<half, double>::scaleToA(half a)
321//{
322// return a;
323//}
324
325//template<>
326//inline float KoColorSpaceMaths<half, float>::scaleToA(half a)
327//{
328// return a;
329//}
330
331//template<>
332//inline half KoColorSpaceMaths<float, half>::scaleToA(float a)
333//{
334// return (half) a;
335//}
336
337//template<>
338//inline quint8 KoColorSpaceMaths<half, quint8>::scaleToA(half a)
339//{
340// half v = a * 255;
341// return (quint8)(CLAMP(v, 0, 255));
342//}
343
344//template<>
345//inline half KoColorSpaceMaths<quint8, half>::scaleToA(quint8 a)
346//{
347// return a *(1.0 / 255.0);
348//}
349//template<>
350//inline quint16 KoColorSpaceMaths<half, quint16>::scaleToA(half a)
351//{
352// double v = a * 0xFFFF;
353// return (quint16)(CLAMP(v, 0, 0xFFFF));
354//}
355
356//template<>
357//inline half KoColorSpaceMaths<quint16, half>::scaleToA(quint16 a)
358//{
359// return a *(1.0 / 0xFFFF);
360//}
361
362//template<>
363//inline half KoColorSpaceMaths<half, half>::scaleToA(half a)
364//{
365// return a;
366//}
367
368//template<>
369//inline half KoColorSpaceMaths<half>::blend(half a, half b, half alpha)
370//{
371// return (a - b) * alpha + b;
372//}
373
374//template<>
375//inline double KoColorSpaceMaths<half>::clamp(double a)
376//{
377// return a;
378//}
379
380
381//#endif
382
384
385//template<>
386//inline quint8 KoColorSpaceMaths<quint8>::multiply(quint8 a, quint8 b)
387//{
388// return (quint8)UINT8_MULT(a, b);
389//}
390
391
392//template<>
393//inline quint8 KoColorSpaceMaths<quint8>::multiply(quint8 a, quint8 b, quint8 c)
394//{
395// return (quint8)UINT8_MULT3(a, b, c);
396//}
397
398//template<>
399//inline KoColorSpaceMathsTraits<quint8>::compositetype
400//KoColorSpaceMaths<quint8>::divide(quint8 a, quint8 b)
401//{
402// return UINT8_DIVIDE(a, b);
403//}
404
405//template<>
406//inline quint8 KoColorSpaceMaths<quint8>::invert(quint8 a)
407//{
408// return ~a;
409//}
410
411//template<>
412//inline quint8 KoColorSpaceMaths<quint8>::blend(quint8 a, quint8 b, quint8 c)
413//{
414// return UINT8_BLEND(a, b, c);
415//}
416
418
419//template<>
420//inline quint16 KoColorSpaceMaths<quint16>::multiply(quint16 a, quint16 b)
421//{
422// return (quint16)UINT16_MULT(a, b);
423//}
424
425//template<>
426//inline KoColorSpaceMathsTraits<quint16>::compositetype
427//KoColorSpaceMaths<quint16>::divide(quint16 a, quint16 b)
428//{
429// return UINT16_DIVIDE(a, b);
430//}
431
432//template<>
433//inline quint16 KoColorSpaceMaths<quint16>::invert(quint16 a)
434//{
435// return ~a;
436//}
437
439
440
442
444//template<>
445//inline quint16 KoColorSpaceMaths<quint8, quint16>::scaleToA(quint8 a)
446//{
447// return UINT8_TO_UINT16(a);
448//}
449
450//template<>
451//inline quint8 KoColorSpaceMaths<quint16, quint8>::scaleToA(quint16 a)
452//{
453// return UINT16_TO_UINT8(a);
454//}
455
456
458
459//template<>
460//inline quint8 KoColorSpaceMaths<quint8, quint8>::scaleToA(quint8 a)
461//{
462// return a;
463//}
464
465//template<>
466//inline quint16 KoColorSpaceMaths<quint16, quint16>::scaleToA(quint16 a)
467//{
468// return a;
469//}
470
471//template<>
472//inline float KoColorSpaceMaths<float, float>::scaleToA(float a)
473//{
474// return a;
475//}
476
477//namespace Arithmetic
478//{
479// const static qreal pi = 3.14159265358979323846;
480
481// template<class T>
482// inline T mul(T a, T b) { return KoColorSpaceMaths<T>::multiply(a, b); }
483
484// template<class T>
485// inline T mul(T a, T b, T c) { return KoColorSpaceMaths<T>::multiply(a, b, c); }
486
498
499// template<class T>
500// inline T inv(T a) { return KoColorSpaceMaths<T>::invert(a); }
501
502// template<class T>
503// inline T lerp(T a, T b, T alpha) { return KoColorSpaceMaths<T>::blend(b, a, alpha); }
504
505// template<class TRet, class T>
506// inline TRet scale(T a) { return KoColorSpaceMaths<T,TRet>::scaleToA(a); }
507
508// template<class T>
509// inline typename KoColorSpaceMathsTraits<T>::compositetype
510// div(T a, T b) { return KoColorSpaceMaths<T>::divide(a, b); }
511
512// template<class T>
513// inline T clamp(typename KoColorSpaceMathsTraits<T>::compositetype a) {
514// return KoColorSpaceMaths<T>::clamp(a);
515// }
516
517// template<class T>
518// inline T min(T a, T b, T c) {
519// b = (a < b) ? a : b;
520// return (b < c) ? b : c;
521// }
522
523// template<class T>
524// inline T max(T a, T b, T c) {
525// b = (a > b) ? a : b;
526// return (b > c) ? b : c;
527// }
528
529// template<class T>
530// inline T zeroValue() { return KoColorSpaceMathsTraits<T>::zeroValue; }
531
532// template<class T>
533// inline T halfValue() { return KoColorSpaceMathsTraits<T>::halfValue; }
534
535// template<class T>
536// inline T unitValue() { return KoColorSpaceMathsTraits<T>::unitValue; }
537
538// template<class T>
539// inline T unionShapeOpacity(T a, T b) {
540// typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
541// return T(composite_type(a) + b - mul(a,b));
542// }
543
544// template<class T>
545// inline T blend(T src, T srcAlpha, T dst, T dstAlpha, T cfValue) {
546// return mul(inv(srcAlpha), dstAlpha, dst) + mul(inv(dstAlpha), srcAlpha, src) + mul(dstAlpha, srcAlpha, cfValue);
547// }
548//}
549
550//struct HSYType
551//{
552// template<class TReal>
553// inline static TReal getLightness(TReal r, TReal g, TReal b) {
554// return TReal(0.299)*r + TReal(0.587)*g + TReal(0.114)*b;
555// }
556
557// template<class TReal>
558// inline static TReal getSaturation(TReal r, TReal g, TReal b) {
559// return Arithmetic::max(r,g,b) - Arithmetic::min(r,g,b);
560// }
561//};
562
563//struct HSIType
564//{
565// template<class TReal>
566// inline static TReal getLightness(TReal r, TReal g, TReal b) {
567// return (r + g + b) * TReal(0.33333333333333333333); // (r + g + b) / 3.0
568// }
569
570// template<class TReal>
571// inline static TReal getSaturation(TReal r, TReal g, TReal b) {
572// TReal max = Arithmetic::max(r, g, b);
573// TReal min = Arithmetic::min(r, g, b);
574// TReal chroma = max - min;
575
576// return (chroma > std::numeric_limits<TReal>::epsilon()) ?
577// (TReal(1.0) - min / getLightness(r, g, b)) : TReal(0.0);
578// }
579//};
580
581//struct HSLType
582//{
583// template<class TReal>
584// inline static TReal getLightness(TReal r, TReal g, TReal b) {
585// TReal max = Arithmetic::max(r, g, b);
586// TReal min = Arithmetic::min(r, g, b);
587// return (max + min) * TReal(0.5);
588// }
589
590// template<class TReal>
591// inline static TReal getSaturation(TReal r, TReal g, TReal b) {
592// TReal max = Arithmetic::max(r, g, b);
593// TReal min = Arithmetic::min(r, g, b);
594// TReal chroma = max - min;
595// TReal light = (max + min) * TReal(0.5);
596// TReal div = TReal(1.0) - std::abs(TReal(2.0)*light - TReal(1.0));
597
598// if(div > std::numeric_limits<TReal>::epsilon())
599// return chroma / div;
600
601// return TReal(1.0);
602// }
603//};
604
605//struct HSVType
606//{
607// template<class TReal>
608// inline static TReal getLightness(TReal r, TReal g, TReal b) {
609// return Arithmetic::max(r,g,b);
610// }
611
612// template<class TReal>
613// inline static TReal getSaturation(TReal r, TReal g, TReal b) {
614// TReal max = Arithmetic::max(r, g, b);
615// TReal min = Arithmetic::min(r, g, b);
616// return (max == TReal(0.0)) ? TReal(0.0) : (max - min) / max;
617// }
618//};
619
620//template<class TReal>
621//TReal getHue(TReal r, TReal g, TReal b) {
622// TReal min = Arithmetic::min(r, g, b);
623// TReal max = Arithmetic::max(r, g, b);
624// TReal chroma = max - min;
625
626// TReal hue = TReal(-1.0);
627
628// if(chroma > std::numeric_limits<TReal>::epsilon()) {
629
631
632// if(max == r) // between yellow and magenta
633// hue = (g - b) / chroma;
634// else if(max == g) // between cyan and yellow
635// hue = TReal(2.0) + (b - r) / chroma;
636// else if(max == b) // between magenta and cyan
637// hue = TReal(4.0) + (r - g) / chroma;
638
639// if(hue < -std::numeric_limits<TReal>::epsilon())
640// hue += TReal(6.0);
641
642// hue /= TReal(6.0);
643// }
644
646
647// return hue;
648//}
649
650//template<class TReal>
651//void getRGB(TReal& r, TReal& g, TReal& b, TReal hue) {
652// // 0 red -> (1,0,0)
653// // 1 yellow -> (1,1,0)
654// // 2 green -> (0,1,0)
655// // 3 cyan -> (0,1,1)
656// // 4 blue -> (0,0,1)
657// // 5 magenta -> (1,0,1)
658// // 6 red -> (1,0,0)
659
660// if(hue < -std::numeric_limits<TReal>::epsilon()) {
661// r = g = b = TReal(0.0);
662// return;
663// }
664
665// int i = int(hue * TReal(6.0));
666// TReal x = hue * TReal(6.0) - i;
667// TReal y = TReal(1.0) - x;
668
669// switch(i % 6){
670// case 0: { r=TReal(1.0), g=x , b=TReal(0.0); } break;
671// case 1: { r=y , g=TReal(1.0), b=TReal(0.0); } break;
672// case 2: { r=TReal(0.0), g=TReal(1.0), b=x ; } break;
673// case 3: { r=TReal(0.0), g=y , b=TReal(1.0); } break;
674// case 4: { r=x , g=TReal(0.0), b=TReal(1.0); } break;
675// case 5: { r=TReal(1.0), g=TReal(0.0), b=y ; } break;
676// }
677//}
678
679//template<class HSXType, class TReal>
680//inline static TReal getLightness(TReal r, TReal g, TReal b) {
681// return HSXType::getLightness(r, g, b);
682//}
683
684//template<class HSXType, class TReal>
685//inline void addLightness(TReal& r, TReal& g, TReal& b, TReal light)
686//{
687// using namespace Arithmetic;
688
689// r += light;
690// g += light;
691// b += light;
692
693// TReal l = HSXType::getLightness(r, g, b);
694// TReal n = min(r, g, b);
695// TReal x = max(r, g, b);
696
697// if(n < TReal(0.0)) {
698// TReal iln = TReal(1.0) / (l-n);
699// r = l + ((r-l) * l) * iln;
700// g = l + ((g-l) * l) * iln;
701// b = l + ((b-l) * l) * iln;
702// }
703
704// if(x > TReal(1.0) && (x-l) > std::numeric_limits<TReal>::epsilon()) {
705// TReal il = TReal(1.0) - l;
706// TReal ixl = TReal(1.0) / (x - l);
707// r = l + ((r-l) * il) * ixl;
708// g = l + ((g-l) * il) * ixl;
709// b = l + ((b-l) * il) * ixl;
710// }
711//}
712
713//template<class HSXType, class TReal>
714//inline void setLightness(TReal& r, TReal& g, TReal& b, TReal light)
715//{
716// addLightness<HSXType>(r,g,b, light - HSXType::getLightness(r,g,b));
717//}
718
719//template<class HSXType, class TReal>
720//inline static TReal getSaturation(TReal r, TReal g, TReal b) {
721// return HSXType::getSaturation(r, g, b);
722//}
723
724//template<class HSXType, class TReal>
725//inline void setSaturation(TReal& r, TReal& g, TReal& b, TReal sat)
726//{
727// int min = 0;
728// int mid = 1;
729// int max = 2;
730// TReal rgb[3] = {r, g, b};
731
732// if(rgb[mid] < rgb[min]) {
733// int tmp = min;
734// min = mid;
735// mid = tmp;
736// }
737
738// if(rgb[max] < rgb[mid]) {
739// int tmp = mid;
740// mid = max;
741// max = tmp;
742// }
743
744// if(rgb[mid] < rgb[min]) {
745// int tmp = min;
746// min = mid;
747// mid = tmp;
748// }
749
750// if((rgb[max] - rgb[min]) > TReal(0.0)) {
751// rgb[mid] = ((rgb[mid]-rgb[min]) * sat) / (rgb[max]-rgb[min]);
752// rgb[max] = sat;
753// rgb[min] = TReal(0.0);
754
755// r = rgb[0];
756// g = rgb[1];
757// b = rgb[2];
758// }
759// else r = g = b = TReal(0.0);
760//}
761
762#endif