Warning, file /office/calligra/libs/pigment/KoColorSpaceMaths.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * Copyright (c) 2006,2007,2010 Cyrille Berger <cberger@cberger.bet 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #ifndef KOCOLORSPACEMATHS_H_ 0021 #define KOCOLORSPACEMATHS_H_ 0022 0023 #include <cmath> 0024 #include <limits> 0025 0026 #include "pigment_export.h" 0027 #include <KoIntegerMaths.h> 0028 #include "KoChannelInfo.h" 0029 #include "KoLut.h" 0030 0031 #undef _T 0032 0033 /** 0034 * This is an empty mainWindow that needs to be "specialized" for each possible 0035 * numerical type (quint8, quint16...). 0036 * 0037 * It needs to defines some static constant fields : 0038 * - zeroValue : the zero for this numerical type 0039 * - unitValue : the maximum value of the normal dynamic range 0040 * - max : the maximum value 0041 * - min : the minimum value 0042 * - epsilon : a value close to zero but different of zero 0043 * - bits : the bit depth 0044 * 0045 * And some types : 0046 * - compositetype the type used for composite operations (usually one with 0047 * a higher bit depth) 0048 */ 0049 template<typename _T> 0050 class KoColorSpaceMathsTraits 0051 { 0052 public: 0053 }; 0054 0055 template<> 0056 class PIGMENTCMS_EXPORT KoColorSpaceMathsTraits<quint8> 0057 { 0058 public: 0059 typedef qint32 compositetype; 0060 static const quint8 zeroValue = 0; 0061 static const quint8 unitValue = 0x00FF; 0062 static const quint8 halfValue = 0x00FF / 2; 0063 static const quint8 max = 0x00FF; 0064 static const quint8 min = 0; 0065 static const quint8 epsilon = 1; 0066 static const qint8 bits = 8; 0067 static const KoChannelInfo::enumChannelValueType channelValueType; 0068 }; 0069 0070 template<> 0071 class PIGMENTCMS_EXPORT KoColorSpaceMathsTraits<quint16> 0072 { 0073 public: 0074 typedef qint64 compositetype; 0075 static const quint16 zeroValue = 0; 0076 static const quint16 unitValue = 0xFFFF; 0077 static const quint16 halfValue = 0xFFFF / 2; 0078 static const quint16 max = 0xFFFF; 0079 static const quint16 min = 0; 0080 static const quint16 epsilon = 1; 0081 static const qint8 bits = 16; 0082 static const KoChannelInfo::enumChannelValueType channelValueType; 0083 }; 0084 0085 template<> 0086 class PIGMENTCMS_EXPORT KoColorSpaceMathsTraits<qint16> 0087 { 0088 public: 0089 typedef qint64 compositetype; 0090 static const qint16 zeroValue = 0; 0091 static const qint16 unitValue = 32767; 0092 static const qint16 halfValue = 32767 / 2; 0093 static const qint16 max = 32767; 0094 static const qint16 min = -32768; 0095 static const qint16 epsilon = 1; 0096 static const qint8 bits = 16; 0097 static const KoChannelInfo::enumChannelValueType channelValueType; 0098 }; 0099 0100 template<> 0101 class PIGMENTCMS_EXPORT KoColorSpaceMathsTraits<quint32> 0102 { 0103 public: 0104 typedef qint64 compositetype; 0105 static const quint32 zeroValue = 0; 0106 static const quint32 unitValue = 0xFFFFFFFF; 0107 static const quint32 halfValue = 0xFFFFFFFF / 2; 0108 static const quint32 max = 0xFFFFFFFF; 0109 static const quint32 min = 0; 0110 static const quint32 epsilon = 1; 0111 static const qint8 bits = 32; 0112 static const KoChannelInfo::enumChannelValueType channelValueType; 0113 }; 0114 0115 #include <KoConfig.h> 0116 #ifdef HAVE_OPENEXR 0117 #include <half.h> 0118 0119 template<> 0120 class PIGMENTCMS_EXPORT KoColorSpaceMathsTraits<half> 0121 { 0122 public: 0123 typedef double compositetype; 0124 static const half zeroValue; 0125 static const half unitValue; 0126 static const half halfValue; 0127 static const half max; 0128 static const half min; 0129 static const half epsilon; 0130 static const qint8 bits = 16; 0131 static const KoChannelInfo::enumChannelValueType channelValueType; 0132 }; 0133 #endif 0134 0135 template<> 0136 class PIGMENTCMS_EXPORT KoColorSpaceMathsTraits<float> 0137 { 0138 public: 0139 typedef double compositetype; 0140 static const float zeroValue; 0141 static const float unitValue; 0142 static const float halfValue; 0143 static const float max; 0144 static const float min; 0145 static const float epsilon; 0146 static const qint8 bits = 32; 0147 static const KoChannelInfo::enumChannelValueType channelValueType; 0148 }; 0149 0150 template<> 0151 class PIGMENTCMS_EXPORT KoColorSpaceMathsTraits<double> 0152 { 0153 public: 0154 typedef double compositetype; 0155 static const double zeroValue; 0156 static const double unitValue; 0157 static const double halfValue; 0158 static const double max; 0159 static const double min; 0160 static const double epsilon; 0161 static const qint8 bits = 64; 0162 static const KoChannelInfo::enumChannelValueType channelValueType; 0163 }; 0164 0165 #ifdef Q_CC_MSVC 0166 // MSVC do not have lrint 0167 0168 const double _double2fixmagic = 68719476736.0*1.5; 0169 const qint32 _shiftamt = 16; //16.16 fixed point representation, 0170 0171 #if Q_BYTE_ORDER == Q_BIG_ENDIAN 0172 #define iexp_ 0 0173 #define iman_ 1 0174 #else 0175 #define iexp_ 1 0176 #define iman_ 0 0177 #endif //BigEndian_ 0178 0179 inline int float2int(double val) 0180 { 0181 val = val + _double2fixmagic; 0182 return ((int*)&val)[iman_] >> _shiftamt; 0183 } 0184 0185 inline int float2int(float val) 0186 { 0187 return float2int((double)val); 0188 } 0189 0190 #else 0191 0192 inline int float2int(float x) 0193 { 0194 return lrintf(x); 0195 } 0196 0197 inline int float2int(double x) 0198 { 0199 return lrint(x); 0200 } 0201 0202 #endif 0203 0204 template<typename _T_> 0205 struct KoIntegerToFloat { 0206 inline float operator()(_T_ f) const 0207 { 0208 return f / float(KoColorSpaceMathsTraits<_T_>::max); 0209 } 0210 }; 0211 0212 struct KoLuts { 0213 0214 static PIGMENTCMS_EXPORT const Ko::FullLut< KoIntegerToFloat<quint16>, float, quint16> Uint16ToFloat; 0215 static PIGMENTCMS_EXPORT const Ko::FullLut< KoIntegerToFloat<quint8>, float, quint8> Uint8ToFloat; 0216 }; 0217 0218 /** 0219 * This class defines some elementary operations used by various color 0220 * space. It's intended to be generic, but some specialization exists 0221 * either for optimization or just for being buildable. 0222 * 0223 * @param _T some numerical type with an existing trait 0224 * @param _Tdst some other numerical type with an existing trait, it is 0225 * only needed if different of _T 0226 */ 0227 template < typename _T, typename _Tdst = _T > 0228 class KoColorSpaceMaths 0229 { 0230 typedef KoColorSpaceMathsTraits<_T> traits; 0231 typedef typename traits::compositetype src_compositetype; 0232 typedef typename KoColorSpaceMathsTraits<_Tdst>::compositetype dst_compositetype; 0233 0234 public: 0235 inline static _Tdst multiply(_T a, _Tdst b) { 0236 return (dst_compositetype(a)*b) / KoColorSpaceMathsTraits<_Tdst>::unitValue; 0237 } 0238 0239 inline static _Tdst multiply(_T a, _Tdst b, _Tdst c) { 0240 return (dst_compositetype(a)*b*c) / (dst_compositetype(KoColorSpaceMathsTraits<_Tdst>::unitValue) * KoColorSpaceMathsTraits<_T>::unitValue); 0241 } 0242 0243 /** 0244 * Division : (a * MAX ) / b 0245 * @param a 0246 * @param b 0247 */ 0248 inline static dst_compositetype divide(_T a, _Tdst b) { 0249 return (dst_compositetype(a) * KoColorSpaceMathsTraits<_Tdst>::unitValue) / b; 0250 } 0251 0252 /** 0253 * Inversion : unitValue - a 0254 * @param a 0255 */ 0256 inline static _T invert(_T a) { 0257 return traits::unitValue - a; 0258 } 0259 0260 /** 0261 * Blending : (a * alpha) + b * (1 - alpha) 0262 * @param a 0263 * @param b 0264 * @param alpha 0265 */ 0266 inline static _T blend(_T a, _T b, _T alpha) { 0267 src_compositetype c = ((src_compositetype(a) - b) * alpha) / traits::unitValue; 0268 return c + b; 0269 } 0270 0271 /** 0272 * This function will scale a value of type _T to fit into a _Tdst. 0273 */ 0274 inline static _Tdst scaleToA(_T a) { 0275 return _Tdst(dst_compositetype(a) * KoColorSpaceMathsTraits<_Tdst>::unitValue / KoColorSpaceMathsTraits<_T>::unitValue); 0276 } 0277 0278 inline static dst_compositetype clamp(dst_compositetype val) { 0279 return qBound<dst_compositetype>(KoColorSpaceMathsTraits<_Tdst>::min, val, KoColorSpaceMathsTraits<_Tdst>::max); 0280 } 0281 0282 /** 0283 * Clamps the composite type on higher border only. That is a fast path 0284 * for scale-only transformations 0285 */ 0286 inline static _Tdst clampAfterScale(dst_compositetype val) { 0287 return qMin<dst_compositetype>(val, KoColorSpaceMathsTraits<_Tdst>::max); 0288 } 0289 }; 0290 0291 //------------------------------ double specialization ------------------------------// 0292 template<> 0293 inline quint8 KoColorSpaceMaths<double, quint8>::scaleToA(double a) 0294 { 0295 double v = a * 255; 0296 return float2int(CLAMP(v, 0, 255)); 0297 } 0298 0299 template<> 0300 inline double KoColorSpaceMaths<quint8, double>::scaleToA(quint8 a) 0301 { 0302 return KoLuts::Uint8ToFloat(a); 0303 } 0304 0305 template<> 0306 inline quint16 KoColorSpaceMaths<double, quint16>::scaleToA(double a) 0307 { 0308 double v = a * 0xFFFF; 0309 return float2int(CLAMP(v, 0, 0xFFFF)); 0310 } 0311 0312 template<> 0313 inline double KoColorSpaceMaths<quint16, double>::scaleToA(quint16 a) 0314 { 0315 return KoLuts::Uint16ToFloat(a); 0316 } 0317 0318 template<> 0319 inline double KoColorSpaceMaths<double>::clamp(double a) 0320 { 0321 return a; 0322 } 0323 0324 //------------------------------ float specialization ------------------------------// 0325 0326 template<> 0327 inline float KoColorSpaceMaths<double, float>::scaleToA(double a) 0328 { 0329 return (float)a; 0330 } 0331 0332 template<> 0333 inline double KoColorSpaceMaths<float, double>::scaleToA(float a) 0334 { 0335 return a; 0336 } 0337 0338 template<> 0339 inline quint16 KoColorSpaceMaths<float, quint16>::scaleToA(float a) 0340 { 0341 float v = a * 0xFFFF; 0342 return (quint16)float2int(CLAMP(v, 0, 0xFFFF)); 0343 } 0344 0345 template<> 0346 inline float KoColorSpaceMaths<quint16, float>::scaleToA(quint16 a) 0347 { 0348 return KoLuts::Uint16ToFloat(a); 0349 } 0350 0351 template<> 0352 inline quint8 KoColorSpaceMaths<float, quint8>::scaleToA(float a) 0353 { 0354 float v = a * 255; 0355 return (quint8)float2int(CLAMP(v, 0, 255)); 0356 } 0357 0358 template<> 0359 inline float KoColorSpaceMaths<quint8, float>::scaleToA(quint8 a) 0360 { 0361 return KoLuts::Uint8ToFloat(a); 0362 } 0363 0364 template<> 0365 inline float KoColorSpaceMaths<float>::blend(float a, float b, float alpha) 0366 { 0367 return (a - b) * alpha + b; 0368 } 0369 0370 template<> 0371 inline double KoColorSpaceMaths<float>::clamp(double a) 0372 { 0373 return a; 0374 } 0375 0376 //------------------------------ half specialization ------------------------------// 0377 0378 #ifdef HAVE_OPENEXR 0379 0380 template<> 0381 inline half KoColorSpaceMaths<double, half>::scaleToA(double a) 0382 { 0383 return (half)a; 0384 } 0385 0386 template<> 0387 inline double KoColorSpaceMaths<half, double>::scaleToA(half a) 0388 { 0389 return a; 0390 } 0391 0392 template<> 0393 inline float KoColorSpaceMaths<half, float>::scaleToA(half a) 0394 { 0395 return a; 0396 } 0397 0398 template<> 0399 inline half KoColorSpaceMaths<float, half>::scaleToA(float a) 0400 { 0401 return (half) a; 0402 } 0403 0404 template<> 0405 inline quint8 KoColorSpaceMaths<half, quint8>::scaleToA(half a) 0406 { 0407 half v = a * 255; 0408 return (quint8)(CLAMP(v, 0, 255)); 0409 } 0410 0411 template<> 0412 inline half KoColorSpaceMaths<quint8, half>::scaleToA(quint8 a) 0413 { 0414 return a *(1.0 / 255.0); 0415 } 0416 template<> 0417 inline quint16 KoColorSpaceMaths<half, quint16>::scaleToA(half a) 0418 { 0419 double v = a * 0xFFFF; 0420 return (quint16)(CLAMP(v, 0, 0xFFFF)); 0421 } 0422 0423 template<> 0424 inline half KoColorSpaceMaths<quint16, half>::scaleToA(quint16 a) 0425 { 0426 return a *(1.0 / 0xFFFF); 0427 } 0428 0429 template<> 0430 inline half KoColorSpaceMaths<half, half>::scaleToA(half a) 0431 { 0432 return a; 0433 } 0434 0435 template<> 0436 inline half KoColorSpaceMaths<half>::blend(half a, half b, half alpha) 0437 { 0438 return (a - b) * alpha + b; 0439 } 0440 0441 template<> 0442 inline double KoColorSpaceMaths<half>::clamp(double a) 0443 { 0444 return a; 0445 } 0446 0447 0448 #endif 0449 0450 //------------------------------ quint8 specialization ------------------------------// 0451 0452 template<> 0453 inline quint8 KoColorSpaceMaths<quint8>::multiply(quint8 a, quint8 b) 0454 { 0455 return (quint8)UINT8_MULT(a, b); 0456 } 0457 0458 0459 template<> 0460 inline quint8 KoColorSpaceMaths<quint8>::multiply(quint8 a, quint8 b, quint8 c) 0461 { 0462 return (quint8)UINT8_MULT3(a, b, c); 0463 } 0464 0465 template<> 0466 inline KoColorSpaceMathsTraits<quint8>::compositetype 0467 KoColorSpaceMaths<quint8>::divide(quint8 a, quint8 b) 0468 { 0469 return UINT8_DIVIDE(a, b); 0470 } 0471 0472 template<> 0473 inline quint8 KoColorSpaceMaths<quint8>::invert(quint8 a) 0474 { 0475 return ~a; 0476 } 0477 0478 template<> 0479 inline quint8 KoColorSpaceMaths<quint8>::blend(quint8 a, quint8 b, quint8 c) 0480 { 0481 return UINT8_BLEND(a, b, c); 0482 } 0483 0484 //------------------------------ quint16 specialization ------------------------------// 0485 0486 template<> 0487 inline quint16 KoColorSpaceMaths<quint16>::multiply(quint16 a, quint16 b) 0488 { 0489 return (quint16)UINT16_MULT(a, b); 0490 } 0491 0492 template<> 0493 inline KoColorSpaceMathsTraits<quint16>::compositetype 0494 KoColorSpaceMaths<quint16>::divide(quint16 a, quint16 b) 0495 { 0496 return UINT16_DIVIDE(a, b); 0497 } 0498 0499 template<> 0500 inline quint16 KoColorSpaceMaths<quint16>::invert(quint16 a) 0501 { 0502 return ~a; 0503 } 0504 0505 //------------------------------ various specialization ------------------------------// 0506 0507 0508 // TODO: use more functions from KoIntegersMaths to do the computation 0509 0510 /// This specialization is needed because the default implementation won't work when scaling up 0511 template<> 0512 inline quint16 KoColorSpaceMaths<quint8, quint16>::scaleToA(quint8 a) 0513 { 0514 return UINT8_TO_UINT16(a); 0515 } 0516 0517 template<> 0518 inline quint8 KoColorSpaceMaths<quint16, quint8>::scaleToA(quint16 a) 0519 { 0520 return UINT16_TO_UINT8(a); 0521 } 0522 0523 0524 // Due to once again a bug in gcc, there is the need for those specialized functions: 0525 0526 template<> 0527 inline quint8 KoColorSpaceMaths<quint8, quint8>::scaleToA(quint8 a) 0528 { 0529 return a; 0530 } 0531 0532 template<> 0533 inline quint16 KoColorSpaceMaths<quint16, quint16>::scaleToA(quint16 a) 0534 { 0535 return a; 0536 } 0537 0538 template<> 0539 inline float KoColorSpaceMaths<float, float>::scaleToA(float a) 0540 { 0541 return a; 0542 } 0543 0544 namespace Arithmetic 0545 { 0546 const static qreal pi = 3.14159265358979323846; 0547 0548 template<class T> 0549 inline T mul(T a, T b) { return KoColorSpaceMaths<T>::multiply(a, b); } 0550 0551 template<class T> 0552 inline T mul(T a, T b, T c) { return KoColorSpaceMaths<T>::multiply(a, b, c); } 0553 0554 // template<class T> 0555 // inline T mul(T a, T b) { 0556 // typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; 0557 // return T(composite_type(a) * b / KoColorSpaceMathsTraits<T>::unitValue); 0558 // } 0559 // 0560 // template<class T> 0561 // inline T mul(T a, T b, T c) { 0562 // typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; 0563 // return T((composite_type(a) * b * c) / (composite_type(KoColorSpaceMathsTraits<T>::unitValue) * KoColorSpaceMathsTraits<T>::unitValue)); 0564 // } 0565 0566 template<class T> 0567 inline T inv(T a) { return KoColorSpaceMaths<T>::invert(a); } 0568 0569 template<class T> 0570 inline T lerp(T a, T b, T alpha) { return KoColorSpaceMaths<T>::blend(b, a, alpha); } 0571 0572 template<class TRet, class T> 0573 inline TRet scale(T a) { return KoColorSpaceMaths<T,TRet>::scaleToA(a); } 0574 0575 template<class T> 0576 inline typename KoColorSpaceMathsTraits<T>::compositetype 0577 div(T a, T b) { return KoColorSpaceMaths<T>::divide(a, b); } 0578 0579 template<class T> 0580 inline T clamp(typename KoColorSpaceMathsTraits<T>::compositetype a) { 0581 return KoColorSpaceMaths<T>::clamp(a); 0582 } 0583 0584 template<class T> 0585 inline T min(T a, T b, T c) { 0586 b = (a < b) ? a : b; 0587 return (b < c) ? b : c; 0588 } 0589 0590 template<class T> 0591 inline T max(T a, T b, T c) { 0592 b = (a > b) ? a : b; 0593 return (b > c) ? b : c; 0594 } 0595 0596 template<class T> 0597 inline T zeroValue() { return KoColorSpaceMathsTraits<T>::zeroValue; } 0598 0599 template<class T> 0600 inline T halfValue() { return KoColorSpaceMathsTraits<T>::halfValue; } 0601 0602 template<class T> 0603 inline T unitValue() { return KoColorSpaceMathsTraits<T>::unitValue; } 0604 0605 template<class T> 0606 inline T unionShapeOpacity(T a, T b) { 0607 typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type; 0608 return T(composite_type(a) + b - mul(a,b)); 0609 } 0610 0611 template<class T> 0612 inline T blend(T src, T srcAlpha, T dst, T dstAlpha, T cfValue) { 0613 return mul(inv(srcAlpha), dstAlpha, dst) + mul(inv(dstAlpha), srcAlpha, src) + mul(dstAlpha, srcAlpha, cfValue); 0614 } 0615 } 0616 0617 struct HSYType 0618 { 0619 template<class TReal> 0620 inline static TReal getLightness(TReal r, TReal g, TReal b) { 0621 return TReal(0.299)*r + TReal(0.587)*g + TReal(0.114)*b; 0622 } 0623 0624 template<class TReal> 0625 inline static TReal getSaturation(TReal r, TReal g, TReal b) { 0626 return Arithmetic::max(r,g,b) - Arithmetic::min(r,g,b); 0627 } 0628 }; 0629 0630 struct HSIType 0631 { 0632 template<class TReal> 0633 inline static TReal getLightness(TReal r, TReal g, TReal b) { 0634 return (r + g + b) * TReal(0.33333333333333333333); // (r + g + b) / 3.0 0635 } 0636 0637 template<class TReal> 0638 inline static TReal getSaturation(TReal r, TReal g, TReal b) { 0639 TReal max = Arithmetic::max(r, g, b); 0640 TReal min = Arithmetic::min(r, g, b); 0641 TReal chroma = max - min; 0642 0643 return (chroma > std::numeric_limits<TReal>::epsilon()) ? 0644 (TReal(1.0) - min / getLightness(r, g, b)) : TReal(0.0); 0645 } 0646 }; 0647 0648 struct HSLType 0649 { 0650 template<class TReal> 0651 inline static TReal getLightness(TReal r, TReal g, TReal b) { 0652 TReal max = Arithmetic::max(r, g, b); 0653 TReal min = Arithmetic::min(r, g, b); 0654 return (max + min) * TReal(0.5); 0655 } 0656 0657 template<class TReal> 0658 inline static TReal getSaturation(TReal r, TReal g, TReal b) { 0659 TReal max = Arithmetic::max(r, g, b); 0660 TReal min = Arithmetic::min(r, g, b); 0661 TReal chroma = max - min; 0662 TReal light = (max + min) * TReal(0.5); 0663 TReal div = TReal(1.0) - std::abs(TReal(2.0)*light - TReal(1.0)); 0664 0665 if(div > std::numeric_limits<TReal>::epsilon()) 0666 return chroma / div; 0667 0668 return TReal(1.0); 0669 } 0670 }; 0671 0672 struct HSVType 0673 { 0674 template<class TReal> 0675 inline static TReal getLightness(TReal r, TReal g, TReal b) { 0676 return Arithmetic::max(r,g,b); 0677 } 0678 0679 template<class TReal> 0680 inline static TReal getSaturation(TReal r, TReal g, TReal b) { 0681 TReal max = Arithmetic::max(r, g, b); 0682 TReal min = Arithmetic::min(r, g, b); 0683 return (max == TReal(0.0)) ? TReal(0.0) : (max - min) / max; 0684 } 0685 }; 0686 0687 template<class TReal> 0688 TReal getHue(TReal r, TReal g, TReal b) { 0689 TReal min = Arithmetic::min(r, g, b); 0690 TReal max = Arithmetic::max(r, g, b); 0691 TReal chroma = max - min; 0692 0693 TReal hue = TReal(-1.0); 0694 0695 if(chroma > std::numeric_limits<TReal>::epsilon()) { 0696 0697 // return atan2(TReal(2.0)*r - g - b, TReal(1.73205080756887729353)*(g - b)); 0698 0699 if(max == r) // between yellow and magenta 0700 hue = (g - b) / chroma; 0701 else if(max == g) // between cyan and yellow 0702 hue = TReal(2.0) + (b - r) / chroma; 0703 else if(max == b) // between magenta and cyan 0704 hue = TReal(4.0) + (r - g) / chroma; 0705 0706 if(hue < -std::numeric_limits<TReal>::epsilon()) 0707 hue += TReal(6.0); 0708 0709 hue /= TReal(6.0); 0710 } 0711 0712 // hue = (r == max) ? (b-g) : (g == max) ? TReal(2.0)+(r-b) : TReal(4.0)+(g-r); 0713 0714 return hue; 0715 } 0716 0717 template<class TReal> 0718 void getRGB(TReal& r, TReal& g, TReal& b, TReal hue) { 0719 // 0 red -> (1,0,0) 0720 // 1 yellow -> (1,1,0) 0721 // 2 green -> (0,1,0) 0722 // 3 cyan -> (0,1,1) 0723 // 4 blue -> (0,0,1) 0724 // 5 maenta -> (1,0,1) 0725 // 6 red -> (1,0,0) 0726 0727 if(hue < -std::numeric_limits<TReal>::epsilon()) { 0728 r = g = b = TReal(0.0); 0729 return; 0730 } 0731 0732 int i = int(hue * TReal(6.0)); 0733 TReal x = hue * TReal(6.0) - i; 0734 TReal y = TReal(1.0) - x; 0735 0736 switch(i % 6){ 0737 case 0: { r=TReal(1.0), g=x , b=TReal(0.0); } break; 0738 case 1: { r=y , g=TReal(1.0), b=TReal(0.0); } break; 0739 case 2: { r=TReal(0.0), g=TReal(1.0), b=x ; } break; 0740 case 3: { r=TReal(0.0), g=y , b=TReal(1.0); } break; 0741 case 4: { r=x , g=TReal(0.0), b=TReal(1.0); } break; 0742 case 5: { r=TReal(1.0), g=TReal(0.0), b=y ; } break; 0743 } 0744 } 0745 0746 template<class HSXType, class TReal> 0747 inline static TReal getLightness(TReal r, TReal g, TReal b) { 0748 return HSXType::getLightness(r, g, b); 0749 } 0750 0751 template<class HSXType, class TReal> 0752 inline void addLightness(TReal& r, TReal& g, TReal& b, TReal light) 0753 { 0754 using namespace Arithmetic; 0755 0756 r += light; 0757 g += light; 0758 b += light; 0759 0760 TReal l = HSXType::getLightness(r, g, b); 0761 TReal n = min(r, g, b); 0762 TReal x = max(r, g, b); 0763 0764 if(n < TReal(0.0)) { 0765 TReal iln = TReal(1.0) / (l-n); 0766 r = l + ((r-l) * l) * iln; 0767 g = l + ((g-l) * l) * iln; 0768 b = l + ((b-l) * l) * iln; 0769 } 0770 0771 if(x > TReal(1.0) && (x-l) > std::numeric_limits<TReal>::epsilon()) { 0772 TReal il = TReal(1.0) - l; 0773 TReal ixl = TReal(1.0) / (x - l); 0774 r = l + ((r-l) * il) * ixl; 0775 g = l + ((g-l) * il) * ixl; 0776 b = l + ((b-l) * il) * ixl; 0777 } 0778 } 0779 0780 template<class HSXType, class TReal> 0781 inline void setLightness(TReal& r, TReal& g, TReal& b, TReal light) 0782 { 0783 addLightness<HSXType>(r,g,b, light - HSXType::getLightness(r,g,b)); 0784 } 0785 0786 template<class HSXType, class TReal> 0787 inline static TReal getSaturation(TReal r, TReal g, TReal b) { 0788 return HSXType::getSaturation(r, g, b); 0789 } 0790 0791 template<class HSXType, class TReal> 0792 inline void setSaturation(TReal& r, TReal& g, TReal& b, TReal sat) 0793 { 0794 int min = 0; 0795 int mid = 1; 0796 int max = 2; 0797 TReal rgb[3] = {r, g, b}; 0798 0799 if(rgb[mid] < rgb[min]) { 0800 int tmp = min; 0801 min = mid; 0802 mid = tmp; 0803 } 0804 0805 if(rgb[max] < rgb[mid]) { 0806 int tmp = mid; 0807 mid = max; 0808 max = tmp; 0809 } 0810 0811 if(rgb[mid] < rgb[min]) { 0812 int tmp = min; 0813 min = mid; 0814 mid = tmp; 0815 } 0816 0817 if((rgb[max] - rgb[min]) > TReal(0.0)) { 0818 rgb[mid] = ((rgb[mid]-rgb[min]) * sat) / (rgb[max]-rgb[min]); 0819 rgb[max] = sat; 0820 rgb[min] = TReal(0.0); 0821 0822 r = rgb[0]; 0823 g = rgb[1]; 0824 b = rgb[2]; 0825 } 0826 else r = g = b = TReal(0.0); 0827 } 0828 0829 #endif