diff --git a/libs/pigment/KoLabColorSpaceMaths.h b/libs/pigment/KoLabColorSpaceMaths.h index 2a3b6dd4f7..7160b76040 100644 --- a/libs/pigment/KoLabColorSpaceMaths.h +++ b/libs/pigment/KoLabColorSpaceMaths.h @@ -1,775 +1,775 @@ /* * Copyright (c) 2006,2007,2010 Cyrille Berger * Copyright (c) 2017,2020 L. E. Segovia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOLABCOLORSPACEMATHS_H_ #define KOLABCOLORSPACEMATHS_H_ #include #include #include "kritapigment_export.h" #include #include "KoChannelInfo.h" #include "KoLut.h" #include #undef _T /** * This is an empty mainWindow that needs to be "specialized" for each possible * numerical type (quint8, quint16...). * * It needs to defines some static constant fields : * - zeroValue : the zero for this numerical type * - unitValue : the maximum value of the normal dynamic range * - max : the maximum value * - min : the minimum value * - epsilon : a value close to zero but different of zero * - bits : the bit depth * * And some types : * - compositetype the type used for composite operations (usually one with * a higher bit depth) * * This class is specialized to handle the floating point bounds of the Lab color space. */ template class KoLabColorSpaceMathsTraits { public: }; template<> class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits : public KoColorSpaceMathsTraits { public: static const quint8 zeroValueL = 0; static const quint8 unitValueL = 0x00FF; static const quint8 halfValueL = 0x00FF / 2; static const quint8 zeroValueAB = 0; static const quint8 unitValueAB = 0x00FF; - static const quint8 halfValueAB = 0x00FF / 2; + static const quint8 halfValueAB = 0x0080; }; template<> class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits : public KoColorSpaceMathsTraits { public: static const quint16 zeroValueL = 0; static const quint16 unitValueL = 0xFFFF; static const quint16 halfValueL = 0xFFFF / 2; static const quint16 zeroValueAB = 0; static const quint16 unitValueAB = 0xFFFF; - static const quint16 halfValueAB = 0xFFFF / 2; + static const quint16 halfValueAB = 0x8080; }; template<> class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits : public KoColorSpaceMathsTraits { public: static const qint16 zeroValueL = 0; static const qint16 unitValueL = 32767; static const qint16 halfValueL = 32767 / 2; static const qint16 zeroValueAB = 0; static const qint16 unitValueAB = 32767; - static const qint16 halfValueAB = 32767 / 2; + static const qint16 halfValueAB = 19549; }; template<> class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits : public KoColorSpaceMathsTraits { public: static const quint32 zeroValueL = 0; static const quint32 unitValueL = 0xFFFFFFFF; static const quint32 halfValueL = 0xFFFFFFFF / 2; static const quint32 zeroValueAB = 0; static const quint32 unitValueAB = 0xFFFFFFFF; - static const quint32 halfValueAB = 0xFFFFFFFF / 2; + static const quint32 halfValueAB = 0x80808080; }; #include #ifdef HAVE_OPENEXR #include template<> class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits : public KoColorSpaceMathsTraits { public: static const half zeroValueL; static const half unitValueL; static const half halfValueL; static const half zeroValueAB; static const half unitValueAB; static const half halfValueAB; }; #endif template<> class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits : public KoColorSpaceMathsTraits { public: static const float zeroValueL; static const float unitValueL; static const float halfValueL; static const float zeroValueAB; static const float unitValueAB; static const float halfValueAB; }; template<> class KRITAPIGMENT_EXPORT KoLabColorSpaceMathsTraits : public KoColorSpaceMathsTraits { public: static const double zeroValueL; static const double unitValueL; static const double halfValueL; static const double zeroValueAB; static const double unitValueAB; static const double halfValueAB; }; //template //struct KoIntegerToFloat { // inline float operator()(_T_ f) const // { // return f / float(KoColorSpaceMathsTraits<_T_>::max); // } //}; //struct KoLuts { // static KRITAPIGMENT_EXPORT const Ko::FullLut< KoIntegerToFloat, float, quint16> Uint16ToFloat; // static KRITAPIGMENT_EXPORT const Ko::FullLut< KoIntegerToFloat, float, quint8> Uint8ToFloat; //}; ///** // * This class defines some elementary operations used by various color // * space. It's intended to be generic, but some specialization exists // * either for optimization or just for being buildable. // * // * @param _T some numerical type with an existing trait // * @param _Tdst some other numerical type with an existing trait, it is // * only needed if different of _T // */ //template < typename _T, typename _Tdst = _T > //class KoColorSpaceMaths //{ // typedef KoColorSpaceMathsTraits<_T> traits; // typedef typename traits::compositetype src_compositetype; // typedef typename KoColorSpaceMathsTraits<_Tdst>::compositetype dst_compositetype; //public: // inline static _Tdst multiply(_T a, _Tdst b) { // return (dst_compositetype(a)*b) / KoColorSpaceMathsTraits<_Tdst>::unitValue; // } // inline static _Tdst multiply(_T a, _Tdst b, _Tdst c) { // return (dst_compositetype(a)*b*c) / (dst_compositetype(KoColorSpaceMathsTraits<_Tdst>::unitValue) * KoColorSpaceMathsTraits<_T>::unitValue); // } // /** // * Division : (a * MAX ) / b // * @param a // * @param b // */ // inline static dst_compositetype divide(_T a, _Tdst b) { // return (dst_compositetype(a) * KoColorSpaceMathsTraits<_Tdst>::unitValue) / b; // } // /** // * Inversion : unitValue - a // * @param a // */ // inline static _T invert(_T a) { // return traits::unitValue - a; // } // /** // * Blending : (a * alpha) + b * (1 - alpha) // * @param a // * @param b // * @param alpha // */ // inline static _T blend(_T a, _T b, _T alpha) { // src_compositetype c = ((src_compositetype(a) - b) * alpha) / traits::unitValue; // return c + b; // } // /** // * This function will scale a value of type _T to fit into a _Tdst. // */ // inline static _Tdst scaleToA(_T a) { // return _Tdst(dst_compositetype(a) * KoColorSpaceMathsTraits<_Tdst>::unitValue / KoColorSpaceMathsTraits<_T>::unitValue); // } // inline static dst_compositetype clamp(dst_compositetype val) { // return qBound(KoColorSpaceMathsTraits<_Tdst>::min, val, KoColorSpaceMathsTraits<_Tdst>::max); // } // /** // * Clamps the composite type on higher border only. That is a fast path // * for scale-only transformations // */ // inline static _Tdst clampAfterScale(dst_compositetype val) { // return qMin(val, KoColorSpaceMathsTraits<_Tdst>::max); // } //}; ////------------------------------ double specialization ------------------------------// //template<> //inline quint8 KoColorSpaceMaths::scaleToA(double a) //{ // double v = a * 255; // return float2int(CLAMP(v, 0, 255)); //} //template<> //inline double KoColorSpaceMaths::scaleToA(quint8 a) //{ // return KoLuts::Uint8ToFloat(a); //} //template<> //inline quint16 KoColorSpaceMaths::scaleToA(double a) //{ // double v = a * 0xFFFF; // return float2int(CLAMP(v, 0, 0xFFFF)); //} //template<> //inline double KoColorSpaceMaths::scaleToA(quint16 a) //{ // return KoLuts::Uint16ToFloat(a); //} //template<> //inline double KoColorSpaceMaths::clamp(double a) //{ // return a; //} ////------------------------------ float specialization ------------------------------// //template<> //inline float KoColorSpaceMaths::scaleToA(double a) //{ // return (float)a; //} //template<> //inline double KoColorSpaceMaths::scaleToA(float a) //{ // return a; //} //template<> //inline quint16 KoColorSpaceMaths::scaleToA(float a) //{ // float v = a * 0xFFFF; // return (quint16)float2int(CLAMP(v, 0, 0xFFFF)); //} //template<> //inline float KoColorSpaceMaths::scaleToA(quint16 a) //{ // return KoLuts::Uint16ToFloat(a); //} //template<> //inline quint8 KoColorSpaceMaths::scaleToA(float a) //{ // float v = a * 255; // return (quint8)float2int(CLAMP(v, 0, 255)); //} //template<> //inline float KoColorSpaceMaths::scaleToA(quint8 a) //{ // return KoLuts::Uint8ToFloat(a); //} //template<> //inline float KoColorSpaceMaths::blend(float a, float b, float alpha) //{ // return (a - b) * alpha + b; //} //template<> //inline double KoColorSpaceMaths::clamp(double a) //{ // return a; //} ////------------------------------ half specialization ------------------------------// //#ifdef HAVE_OPENEXR //template<> //inline half KoColorSpaceMaths::scaleToA(double a) //{ // return (half)a; //} //template<> //inline double KoColorSpaceMaths::scaleToA(half a) //{ // return a; //} //template<> //inline float KoColorSpaceMaths::scaleToA(half a) //{ // return a; //} //template<> //inline half KoColorSpaceMaths::scaleToA(float a) //{ // return (half) a; //} //template<> //inline quint8 KoColorSpaceMaths::scaleToA(half a) //{ // half v = a * 255; // return (quint8)(CLAMP(v, 0, 255)); //} //template<> //inline half KoColorSpaceMaths::scaleToA(quint8 a) //{ // return a *(1.0 / 255.0); //} //template<> //inline quint16 KoColorSpaceMaths::scaleToA(half a) //{ // double v = a * 0xFFFF; // return (quint16)(CLAMP(v, 0, 0xFFFF)); //} //template<> //inline half KoColorSpaceMaths::scaleToA(quint16 a) //{ // return a *(1.0 / 0xFFFF); //} //template<> //inline half KoColorSpaceMaths::scaleToA(half a) //{ // return a; //} //template<> //inline half KoColorSpaceMaths::blend(half a, half b, half alpha) //{ // return (a - b) * alpha + b; //} //template<> //inline double KoColorSpaceMaths::clamp(double a) //{ // return a; //} //#endif ////------------------------------ quint8 specialization ------------------------------// //template<> //inline quint8 KoColorSpaceMaths::multiply(quint8 a, quint8 b) //{ // return (quint8)UINT8_MULT(a, b); //} //template<> //inline quint8 KoColorSpaceMaths::multiply(quint8 a, quint8 b, quint8 c) //{ // return (quint8)UINT8_MULT3(a, b, c); //} //template<> //inline KoColorSpaceMathsTraits::compositetype //KoColorSpaceMaths::divide(quint8 a, quint8 b) //{ // return UINT8_DIVIDE(a, b); //} //template<> //inline quint8 KoColorSpaceMaths::invert(quint8 a) //{ // return ~a; //} //template<> //inline quint8 KoColorSpaceMaths::blend(quint8 a, quint8 b, quint8 c) //{ // return UINT8_BLEND(a, b, c); //} ////------------------------------ quint16 specialization ------------------------------// //template<> //inline quint16 KoColorSpaceMaths::multiply(quint16 a, quint16 b) //{ // return (quint16)UINT16_MULT(a, b); //} //template<> //inline KoColorSpaceMathsTraits::compositetype //KoColorSpaceMaths::divide(quint16 a, quint16 b) //{ // return UINT16_DIVIDE(a, b); //} //template<> //inline quint16 KoColorSpaceMaths::invert(quint16 a) //{ // return ~a; //} ////------------------------------ various specialization ------------------------------// //// TODO: use more functions from KoIntegersMaths to do the computation ///// This specialization is needed because the default implementation won't work when scaling up //template<> //inline quint16 KoColorSpaceMaths::scaleToA(quint8 a) //{ // return UINT8_TO_UINT16(a); //} //template<> //inline quint8 KoColorSpaceMaths::scaleToA(quint16 a) //{ // return UINT16_TO_UINT8(a); //} //// Due to once again a bug in gcc, there is the need for those specialized functions: //template<> //inline quint8 KoColorSpaceMaths::scaleToA(quint8 a) //{ // return a; //} //template<> //inline quint16 KoColorSpaceMaths::scaleToA(quint16 a) //{ // return a; //} //template<> //inline float KoColorSpaceMaths::scaleToA(float a) //{ // return a; //} //namespace Arithmetic //{ // const static qreal pi = 3.14159265358979323846; // template // inline T mul(T a, T b) { return KoColorSpaceMaths::multiply(a, b); } // template // inline T mul(T a, T b, T c) { return KoColorSpaceMaths::multiply(a, b, c); } //// template //// inline T mul(T a, T b) { //// typedef typename KoColorSpaceMathsTraits::compositetype composite_type; //// return T(composite_type(a) * b / KoColorSpaceMathsTraits::unitValue); //// } //// //// template //// inline T mul(T a, T b, T c) { //// typedef typename KoColorSpaceMathsTraits::compositetype composite_type; //// return T((composite_type(a) * b * c) / (composite_type(KoColorSpaceMathsTraits::unitValue) * KoColorSpaceMathsTraits::unitValue)); //// } // template // inline T inv(T a) { return KoColorSpaceMaths::invert(a); } // template // inline T lerp(T a, T b, T alpha) { return KoColorSpaceMaths::blend(b, a, alpha); } // template // inline TRet scale(T a) { return KoColorSpaceMaths::scaleToA(a); } // template // inline typename KoColorSpaceMathsTraits::compositetype // div(T a, T b) { return KoColorSpaceMaths::divide(a, b); } // template // inline T clamp(typename KoColorSpaceMathsTraits::compositetype a) { // return KoColorSpaceMaths::clamp(a); // } // template // inline T min(T a, T b, T c) { // b = (a < b) ? a : b; // return (b < c) ? b : c; // } // template // inline T max(T a, T b, T c) { // b = (a > b) ? a : b; // return (b > c) ? b : c; // } // template // inline T zeroValue() { return KoColorSpaceMathsTraits::zeroValue; } // template // inline T halfValue() { return KoColorSpaceMathsTraits::halfValue; } // template // inline T unitValue() { return KoColorSpaceMathsTraits::unitValue; } // template // inline T unionShapeOpacity(T a, T b) { // typedef typename KoColorSpaceMathsTraits::compositetype composite_type; // return T(composite_type(a) + b - mul(a,b)); // } // template // inline T blend(T src, T srcAlpha, T dst, T dstAlpha, T cfValue) { // return mul(inv(srcAlpha), dstAlpha, dst) + mul(inv(dstAlpha), srcAlpha, src) + mul(dstAlpha, srcAlpha, cfValue); // } //} //struct HSYType //{ // template // inline static TReal getLightness(TReal r, TReal g, TReal b) { // return TReal(0.299)*r + TReal(0.587)*g + TReal(0.114)*b; // } // template // inline static TReal getSaturation(TReal r, TReal g, TReal b) { // return Arithmetic::max(r,g,b) - Arithmetic::min(r,g,b); // } //}; //struct HSIType //{ // template // inline static TReal getLightness(TReal r, TReal g, TReal b) { // return (r + g + b) * TReal(0.33333333333333333333); // (r + g + b) / 3.0 // } // template // inline static TReal getSaturation(TReal r, TReal g, TReal b) { // TReal max = Arithmetic::max(r, g, b); // TReal min = Arithmetic::min(r, g, b); // TReal chroma = max - min; // return (chroma > std::numeric_limits::epsilon()) ? // (TReal(1.0) - min / getLightness(r, g, b)) : TReal(0.0); // } //}; //struct HSLType //{ // template // inline static TReal getLightness(TReal r, TReal g, TReal b) { // TReal max = Arithmetic::max(r, g, b); // TReal min = Arithmetic::min(r, g, b); // return (max + min) * TReal(0.5); // } // template // inline static TReal getSaturation(TReal r, TReal g, TReal b) { // TReal max = Arithmetic::max(r, g, b); // TReal min = Arithmetic::min(r, g, b); // TReal chroma = max - min; // TReal light = (max + min) * TReal(0.5); // TReal div = TReal(1.0) - std::abs(TReal(2.0)*light - TReal(1.0)); // if(div > std::numeric_limits::epsilon()) // return chroma / div; // return TReal(1.0); // } //}; //struct HSVType //{ // template // inline static TReal getLightness(TReal r, TReal g, TReal b) { // return Arithmetic::max(r,g,b); // } // template // inline static TReal getSaturation(TReal r, TReal g, TReal b) { // TReal max = Arithmetic::max(r, g, b); // TReal min = Arithmetic::min(r, g, b); // return (max == TReal(0.0)) ? TReal(0.0) : (max - min) / max; // } //}; //template //TReal getHue(TReal r, TReal g, TReal b) { // TReal min = Arithmetic::min(r, g, b); // TReal max = Arithmetic::max(r, g, b); // TReal chroma = max - min; // TReal hue = TReal(-1.0); // if(chroma > std::numeric_limits::epsilon()) { //// return atan2(TReal(2.0)*r - g - b, TReal(1.73205080756887729353)*(g - b)); // if(max == r) // between yellow and magenta // hue = (g - b) / chroma; // else if(max == g) // between cyan and yellow // hue = TReal(2.0) + (b - r) / chroma; // else if(max == b) // between magenta and cyan // hue = TReal(4.0) + (r - g) / chroma; // if(hue < -std::numeric_limits::epsilon()) // hue += TReal(6.0); // hue /= TReal(6.0); // } //// hue = (r == max) ? (b-g) : (g == max) ? TReal(2.0)+(r-b) : TReal(4.0)+(g-r); // return hue; //} //template //void getRGB(TReal& r, TReal& g, TReal& b, TReal hue) { // // 0 red -> (1,0,0) // // 1 yellow -> (1,1,0) // // 2 green -> (0,1,0) // // 3 cyan -> (0,1,1) // // 4 blue -> (0,0,1) // // 5 maenta -> (1,0,1) // // 6 red -> (1,0,0) // if(hue < -std::numeric_limits::epsilon()) { // r = g = b = TReal(0.0); // return; // } // int i = int(hue * TReal(6.0)); // TReal x = hue * TReal(6.0) - i; // TReal y = TReal(1.0) - x; // switch(i % 6){ // case 0: { r=TReal(1.0), g=x , b=TReal(0.0); } break; // case 1: { r=y , g=TReal(1.0), b=TReal(0.0); } break; // case 2: { r=TReal(0.0), g=TReal(1.0), b=x ; } break; // case 3: { r=TReal(0.0), g=y , b=TReal(1.0); } break; // case 4: { r=x , g=TReal(0.0), b=TReal(1.0); } break; // case 5: { r=TReal(1.0), g=TReal(0.0), b=y ; } break; // } //} //template //inline static TReal getLightness(TReal r, TReal g, TReal b) { // return HSXType::getLightness(r, g, b); //} //template //inline void addLightness(TReal& r, TReal& g, TReal& b, TReal light) //{ // using namespace Arithmetic; // r += light; // g += light; // b += light; // TReal l = HSXType::getLightness(r, g, b); // TReal n = min(r, g, b); // TReal x = max(r, g, b); // if(n < TReal(0.0)) { // TReal iln = TReal(1.0) / (l-n); // r = l + ((r-l) * l) * iln; // g = l + ((g-l) * l) * iln; // b = l + ((b-l) * l) * iln; // } // if(x > TReal(1.0) && (x-l) > std::numeric_limits::epsilon()) { // TReal il = TReal(1.0) - l; // TReal ixl = TReal(1.0) / (x - l); // r = l + ((r-l) * il) * ixl; // g = l + ((g-l) * il) * ixl; // b = l + ((b-l) * il) * ixl; // } //} //template //inline void setLightness(TReal& r, TReal& g, TReal& b, TReal light) //{ // addLightness(r,g,b, light - HSXType::getLightness(r,g,b)); //} //template //inline static TReal getSaturation(TReal r, TReal g, TReal b) { // return HSXType::getSaturation(r, g, b); //} //template //inline void setSaturation(TReal& r, TReal& g, TReal& b, TReal sat) //{ // int min = 0; // int mid = 1; // int max = 2; // TReal rgb[3] = {r, g, b}; // if(rgb[mid] < rgb[min]) { // int tmp = min; // min = mid; // mid = tmp; // } // if(rgb[max] < rgb[mid]) { // int tmp = mid; // mid = max; // max = tmp; // } // if(rgb[mid] < rgb[min]) { // int tmp = min; // min = mid; // mid = tmp; // } // if((rgb[max] - rgb[min]) > TReal(0.0)) { // rgb[mid] = ((rgb[mid]-rgb[min]) * sat) / (rgb[max]-rgb[min]); // rgb[max] = sat; // rgb[min] = TReal(0.0); // r = rgb[0]; // g = rgb[1]; // b = rgb[2]; // } // else r = g = b = TReal(0.0); //} #endif diff --git a/libs/pigment/KoLabColorSpaceTraits.h b/libs/pigment/KoLabColorSpaceTraits.h index 9f866b3637..70a6cafe4d 100644 --- a/libs/pigment/KoLabColorSpaceTraits.h +++ b/libs/pigment/KoLabColorSpaceTraits.h @@ -1,204 +1,226 @@ /* * Copyright (c) 2006-2007 Cyrille Berger * Copyright (c) 2016,2017,2020 L. E. Segovia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_LAB_COLORSPACE_TRAITS_H_ #define _KO_LAB_COLORSPACE_TRAITS_H_ #include /** * LAB traits, it provides some convenient functions to * access LAB channels through an explicit API. * * Use this class in conjonction with KoColorSpace::toLabA16 and * KoColorSpace::fromLabA16 data. * * Example: * quint8* p = KoLabU16Traits::allocate(1); * oneKoColorSpace->toLabA16(somepointertodata, p, 1); * KoLabU16Traits::setL( p, KoLabU16Traits::L(p) / 10 ); * oneKoColorSpace->fromLabA16(p, somepointertodata, 1); */ template struct KoLabTraits : public KoColorSpaceTrait<_channels_type_, 4, 3> { typedef _channels_type_ channels_type; typedef KoColorSpaceTrait<_channels_type_, 4, 3> parent; static const qint32 L_pos = 0; static const qint32 a_pos = 1; static const qint32 b_pos = 2; /** * An Lab pixel */ struct Pixel { channels_type L; channels_type a; channels_type b; channels_type alpha; }; /// @return the L component inline static channels_type L(quint8* data) { channels_type* d = parent::nativeArray(data); return d[L_pos]; } /// Set the L component inline static void setL(quint8* data, channels_type nv) { channels_type* d = parent::nativeArray(data); d[L_pos] = nv; } /// @return the a component inline static channels_type a(quint8* data) { channels_type* d = parent::nativeArray(data); return d[a_pos]; } /// Set the a component inline static void setA(quint8* data, channels_type nv) { channels_type* d = parent::nativeArray(data); d[a_pos] = nv; } /// @return the b component inline static channels_type b(quint8* data) { channels_type* d = parent::nativeArray(data); return d[b_pos]; } /// Set the a component inline static void setB(quint8* data, channels_type nv) { channels_type* d = parent::nativeArray(data); d[b_pos] = nv; } // Lab has some... particulars inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) { if (channelIndex > parent::channels_nb) return QString("Error"); channels_type c = parent::nativeArray(pixel)[channelIndex]; switch (channelIndex) { case L_pos: return QString().setNum(100.0 * qBound((qreal)0, ((qreal)c) / KoLabColorSpaceMathsTraits::unitValueL, (qreal)KoLabColorSpaceMathsTraits::unitValueL)); case a_pos: case b_pos: - return QString().setNum(100.0 * - qBound((qreal)KoLabColorSpaceMathsTraits::zeroValueAB, - (((qreal)c) - KoLabColorSpaceMathsTraits::zeroValueAB) / (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::zeroValueAB), - (qreal)KoLabColorSpaceMathsTraits::unitValueAB)); + if (c <= 0.5) { + return QString().setNum(100.0 * + qBound((qreal)KoLabColorSpaceMathsTraits::zeroValueAB, + (qreal)(2.0 * c * KoLabColorSpaceMathsTraits::halfValueAB), + (qreal)KoLabColorSpaceMathsTraits::halfValueAB)); + } else { + return QString().setNum(100.0 * + qBound((qreal)KoLabColorSpaceMathsTraits::halfValueAB, + (qreal)(KoLabColorSpaceMathsTraits::halfValueAB + 2.0 * (c - 0.5) * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)), + (qreal)KoLabColorSpaceMathsTraits::unitValueAB)); + } case 3: return QString().setNum(100.0 * qBound((qreal)0, ((qreal)c) / KoLabColorSpaceMathsTraits::unitValue, (qreal)KoLabColorSpaceMathsTraits::unitValue)); default: return QString("Error"); } } inline static void normalisedChannelsValue(const quint8 *pixel, QVector &channels) { Q_ASSERT((int)channels.count() >= (int)parent::channels_nb); channels_type c; for (uint i = 0; i < parent::channels_nb; i++) { c = parent::nativeArray(pixel)[i]; switch (i) { case L_pos: channels[i] = (qreal)c / KoLabColorSpaceMathsTraits::unitValueL; break; case a_pos: case b_pos: - channels[i] = ((qreal)c - KoLabColorSpaceMathsTraits::zeroValueAB) / (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::zeroValueAB); + if (c <= KoLabColorSpaceMathsTraits::halfValueAB) { + channels[i] = ((qreal)c - KoLabColorSpaceMathsTraits::zeroValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB)); + } else { + channels[i] = 0.5 + ((qreal)c - KoLabColorSpaceMathsTraits::halfValueAB) / (2.0 * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)); + } break; // As per KoChannelInfo alpha channels are [0..1] case 3: default: channels[i] = (qreal)c / KoLabColorSpaceMathsTraits::unitValue; break; } } } inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) { Q_ASSERT((int)values.count() >= (int)parent::channels_nb); channels_type c; for (uint i = 0; i < parent::channels_nb; i++) { float b = 0; switch (i) { case L_pos: - b = qBound((float)KoLabColorSpaceMathsTraits::zeroValueL, (float)KoLabColorSpaceMathsTraits::unitValueL * values[i], (float)KoLabColorSpaceMathsTraits::unitValueL); + b = qBound((float)KoLabColorSpaceMathsTraits::zeroValueL, + (float)KoLabColorSpaceMathsTraits::unitValueL * values[i], + (float)KoLabColorSpaceMathsTraits::unitValueL); break; case a_pos: case b_pos: - b = qBound((float)KoLabColorSpaceMathsTraits::zeroValueAB, - (float)((KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::zeroValueAB) * values[i] + KoLabColorSpaceMathsTraits::zeroValueAB), - (float)KoLabColorSpaceMathsTraits::unitValueAB); + if (values[i] <= 0.5) { + b = qBound((float)KoLabColorSpaceMathsTraits::zeroValueAB, + (float)(KoLabColorSpaceMathsTraits::zeroValueAB + 2.0 * values[i] * (KoLabColorSpaceMathsTraits::halfValueAB - KoLabColorSpaceMathsTraits::zeroValueAB)), + (float)KoLabColorSpaceMathsTraits::halfValueAB); + } + else { + b = qBound((float)KoLabColorSpaceMathsTraits::halfValueAB, + (float)(KoLabColorSpaceMathsTraits::halfValueAB + 2.0 * (values[i] - 0.5) * (KoLabColorSpaceMathsTraits::unitValueAB - KoLabColorSpaceMathsTraits::halfValueAB)), + (float)KoLabColorSpaceMathsTraits::unitValueAB); + } break; case 3: - b = qBound((float)KoLabColorSpaceMathsTraits::min, (float)KoLabColorSpaceMathsTraits::unitValue * values[i], (float)KoLabColorSpaceMathsTraits::max); + b = qBound((float)KoLabColorSpaceMathsTraits::min, + (float)KoLabColorSpaceMathsTraits::unitValue * values[i], + (float)KoLabColorSpaceMathsTraits::unitValue); default: break; } c = (channels_type)b; parent::nativeArray(pixel)[i] = c; } } }; //For quint* values must range from 0 to 1 - see KoColorSpaceMaths // https://github.com/mm2/Little-CMS/blob/master/src/cmspcs.c //PCS in Lab2 is encoded as: // 8 bit Lab PCS: // L* 0..100 into a 0..ff byte. // a* t + 128 range is -128.0 +127.0 // b* // 16 bit Lab PCS: // L* 0..100 into a 0..ff00 word. // a* t + 128 range is -128.0 +127.9961 // b* //Version 4 //--------- //CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffff //CIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff //CIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff struct KoLabU8Traits : public KoLabTraits { }; struct KoLabU16Traits : public KoLabTraits { }; // Float values are normalized to [0..100], [-128..+127], [-128..+127] - out of range values are clipped #include #ifdef HAVE_OPENEXR #include struct KoLabF16Traits : public KoLabTraits { }; #endif struct KoLabF32Traits : public KoLabTraits { }; struct KoLabF64Traits : public KoLabTraits { }; #endif diff --git a/plugins/color/lcms2engine/LcmsEnginePlugin.cpp b/plugins/color/lcms2engine/LcmsEnginePlugin.cpp index 268f220a57..7d862db824 100644 --- a/plugins/color/lcms2engine/LcmsEnginePlugin.cpp +++ b/plugins/color/lcms2engine/LcmsEnginePlugin.cpp @@ -1,316 +1,316 @@ /* * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004,2010 Cyrille Berger * Copyright (c) 2011 Srikanth Tiyyagura * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "LcmsEnginePlugin.h" #include #include #include #include #include #include #include #include #include "kis_assert.h" #include #include #include #include #include "IccColorSpaceEngine.h" #include "colorprofiles/LcmsColorProfileContainer.h" #include "colorspaces/cmyk_u8/CmykU8ColorSpace.h" #include "colorspaces/cmyk_u16/CmykU16ColorSpace.h" #include "colorspaces/cmyk_f32/CmykF32ColorSpace.h" #include "colorspaces/gray_u8/GrayU8ColorSpace.h" #include "colorspaces/gray_u16/GrayU16ColorSpace.h" #include "colorspaces/gray_f32/GrayF32ColorSpace.h" #include "colorspaces/lab_u8/LabU8ColorSpace.h" #include "colorspaces/lab_u16/LabColorSpace.h" #include "colorspaces/lab_f32/LabF32ColorSpace.h" #include "colorspaces/xyz_u8/XyzU8ColorSpace.h" #include "colorspaces/xyz_u16/XyzU16ColorSpace.h" #include "colorspaces/xyz_f32/XyzF32ColorSpace.h" #include "colorspaces/rgb_u8/RgbU8ColorSpace.h" #include "colorspaces/rgb_u16/RgbU16ColorSpace.h" #include "colorspaces/rgb_f32/RgbF32ColorSpace.h" #include "colorspaces/ycbcr_u8/YCbCrU8ColorSpace.h" #include "colorspaces/ycbcr_u16/YCbCrU16ColorSpace.h" #include "colorspaces/ycbcr_f32/YCbCrF32ColorSpace.h" #include "LcmsRGBP2020PQColorSpace.h" #include #ifdef HAVE_OPENEXR # include # ifdef HAVE_LCMS24 # include "colorspaces/gray_f16/GrayF16ColorSpace.h" # include "colorspaces/xyz_f16/XyzF16ColorSpace.h" # include "colorspaces/rgb_f16/RgbF16ColorSpace.h" # endif #endif void lcms2LogErrorHandlerFunction(cmsContext /*ContextID*/, cmsUInt32Number ErrorCode, const char *Text) { qCritical() << "Lcms2 error: " << ErrorCode << Text; } K_PLUGIN_FACTORY_WITH_JSON(PluginFactory, "kolcmsengine.json", registerPlugin();) LcmsEnginePlugin::LcmsEnginePlugin(QObject *parent, const QVariantList &) : QObject(parent) { KoResourcePaths::addResourceType("icc_profiles", "data", "/color/icc"); KoResourcePaths::addResourceType("icc_profiles", "data", "/profiles/"); // Set the lmcs error reporting function cmsSetLogErrorHandler(&lcms2LogErrorHandlerFunction); KoColorSpaceRegistry *registry = KoColorSpaceRegistry::instance(); // Initialise color engine KoColorSpaceEngineRegistry::instance()->add(new IccColorSpaceEngine); QStringList profileFilenames; profileFilenames += KoResourcePaths::findAllResources("icc_profiles", "*.icm", KoResourcePaths::Recursive); profileFilenames += KoResourcePaths::findAllResources("icc_profiles", "*.ICM", KoResourcePaths::Recursive); profileFilenames += KoResourcePaths::findAllResources("icc_profiles", "*.ICC", KoResourcePaths::Recursive); profileFilenames += KoResourcePaths::findAllResources("icc_profiles", "*.icc", KoResourcePaths::Recursive); QStringList iccProfileDirs; #ifdef Q_OS_MAC iccProfileDirs.append(QDir::homePath() + "/Library/ColorSync/Profiles/"); iccProfileDirs.append("/System/Library/ColorSync/Profiles/"); iccProfileDirs.append("/Library/ColorSync/Profiles/"); #endif #ifdef Q_OS_WIN QString winPath = QString::fromUtf8(qgetenv("windir")); winPath.replace('\\','/'); iccProfileDirs.append(winPath + "/System32/Spool/Drivers/Color/"); #endif Q_FOREACH(const QString &iccProfiledir, iccProfileDirs) { QDir profileDir(iccProfiledir); Q_FOREACH(const QString &entry, profileDir.entryList(QStringList() << "*.icm" << "*.icc", QDir::NoDotAndDotDot | QDir::Files | QDir::Readable)) { profileFilenames << iccProfiledir + "/" + entry; } } // Load the profiles if (!profileFilenames.empty()) { for (QStringList::Iterator it = profileFilenames.begin(); it != profileFilenames.end(); ++it) { KoColorProfile *profile = new IccColorProfile(*it); Q_CHECK_PTR(profile); profile->load(); if (profile->valid()) { //qDebug() << "Valid profile : " << profile->fileName() << profile->name(); registry->addProfileToMap(profile); } else { qDebug() << "Invalid profile : " << profile->fileName() << profile->name(); delete profile; } } } // ------------------- LAB --------------------------------- - KoColorProfile *labProfile = LcmsColorProfileContainer::createFromLcmsProfile(cmsCreateLab2Profile(0)); + KoColorProfile *labProfile = LcmsColorProfileContainer::createFromLcmsProfile(cmsCreateLab4Profile(0)); registry->addProfile(labProfile); registry->add(new LabU8ColorSpaceFactory()); registry->add(new LabU16ColorSpaceFactory()); registry->add(new LabF32ColorSpaceFactory()); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("LABAU8HISTO", i18n("L*a*b*/8 Histogram")), LABAColorModelID.id(), Integer8BitsColorDepthID.id())); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("LABAU16HISTO", i18n("L*a*b*/16 Histogram")), LABAColorModelID.id(), Integer16BitsColorDepthID.id())); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("LABAF32HISTO", i18n("L*a*b*/32 Histogram")), LABAColorModelID.id(), Float32BitsColorDepthID.id())); // ------------------- RGB --------------------------------- KoColorProfile *rgbProfile = LcmsColorProfileContainer::createFromLcmsProfile(cmsCreate_sRGBProfile()); registry->addProfile(rgbProfile); registry->add(new LcmsRGBP2020PQColorSpaceFactoryWrapper()); registry->add(new LcmsRGBP2020PQColorSpaceFactoryWrapper()); #ifdef HAVE_LCMS24 #ifdef HAVE_OPENEXR registry->add(new LcmsRGBP2020PQColorSpaceFactoryWrapper()); #endif #endif registry->add(new LcmsRGBP2020PQColorSpaceFactoryWrapper()); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("RGBU8HISTO", i18n("RGBA/8 Histogram")), RGBAColorModelID.id(), Integer8BitsColorDepthID.id())); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("RGBU16HISTO", i18n("RGBA/16 Histogram")), RGBAColorModelID.id(), Integer16BitsColorDepthID.id())); #ifdef HAVE_LCMS24 #ifdef HAVE_OPENEXR KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("RGBF16HISTO", i18n("RGBA/F16 Histogram")), RGBAColorModelID.id(), Float16BitsColorDepthID.id())); #endif #endif KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("RGF328HISTO", i18n("RGBA/F32 Histogram")), RGBAColorModelID.id(), Float32BitsColorDepthID.id())); // ------------------- GRAY --------------------------------- cmsToneCurve *Gamma = cmsBuildGamma(0, 2.2); cmsHPROFILE hProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma); cmsFreeToneCurve(Gamma); KoColorProfile *defProfile = LcmsColorProfileContainer::createFromLcmsProfile(hProfile); registry->addProfile(defProfile); registry->add(new GrayAU8ColorSpaceFactory()); registry->add(new GrayAU16ColorSpaceFactory()); #ifdef HAVE_LCMS24 #ifdef HAVE_OPENEXR registry->add(new GrayF16ColorSpaceFactory()); #endif #endif registry->add(new GrayF32ColorSpaceFactory()); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("GRAYA8HISTO", i18n("GRAY/8 Histogram")), GrayAColorModelID.id(), Integer8BitsColorDepthID.id())); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("GRAYA16HISTO", i18n("GRAY/16 Histogram")), GrayAColorModelID.id(), Integer16BitsColorDepthID.id())); #ifdef HAVE_LCMS24 #ifdef HAVE_OPENEXR KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("GRAYF16HISTO", i18n("GRAYF/F16 Histogram")), GrayAColorModelID.id(), Float16BitsColorDepthID.id())); #endif #endif KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("GRAYAF32HISTO", i18n("GRAY/F32 float Histogram")), GrayAColorModelID.id(), Float32BitsColorDepthID.id())); // ------------------- CMYK --------------------------------- registry->add(new CmykU8ColorSpaceFactory()); registry->add(new CmykU16ColorSpaceFactory()); registry->add(new CmykF32ColorSpaceFactory()); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("CMYK8HISTO", i18n("CMYK/8 Histogram")), CMYKAColorModelID.id(), Integer8BitsColorDepthID.id())); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("CMYK16HISTO", i18n("CMYK/16 Histogram")), CMYKAColorModelID.id(), Integer16BitsColorDepthID.id())); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("CMYKF32HISTO", i18n("CMYK/F32 Histogram")), CMYKAColorModelID.id(), Float32BitsColorDepthID.id())); // ------------------- XYZ --------------------------------- KoColorProfile *xyzProfile = LcmsColorProfileContainer::createFromLcmsProfile(cmsCreateXYZProfile()); registry->addProfile(xyzProfile); registry->add(new XyzU8ColorSpaceFactory()); registry->add(new XyzU16ColorSpaceFactory()); #ifdef HAVE_LCMS24 #ifdef HAVE_OPENEXR registry->add(new XyzF16ColorSpaceFactory()); #endif #endif registry->add(new XyzF32ColorSpaceFactory()); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("XYZ8HISTO", i18n("XYZ/8 Histogram")), XYZAColorModelID.id(), Integer8BitsColorDepthID.id())); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("XYZ16HISTO", i18n("XYZ/16 Histogram")), XYZAColorModelID.id(), Integer16BitsColorDepthID.id())); #ifdef HAVE_LCMS24 #ifdef HAVE_OPENEXR KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("XYZF16HISTO", i18n("XYZ/F16 Histogram")), XYZAColorModelID.id(), Float16BitsColorDepthID.id())); #endif #endif KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("XYZF32HISTO", i18n("XYZF32 Histogram")), XYZAColorModelID.id(), Float32BitsColorDepthID.id())); // ------------------- YCBCR --------------------------------- // KoColorProfile *yCbCrProfile = LcmsColorProfileContainer::createFromLcmsProfile(cmsCreateYCBCRProfile()); // registry->addProfile(yCbCrProfile); registry->add(new YCbCrU8ColorSpaceFactory()); registry->add(new YCbCrU16ColorSpaceFactory()); registry->add(new YCbCrF32ColorSpaceFactory()); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("YCBCR8HISTO", i18n("YCbCr/8 Histogram")), YCbCrAColorModelID.id(), Integer8BitsColorDepthID.id())); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("YCBCR16HISTO", i18n("YCbCr/16 Histogram")), YCbCrAColorModelID.id(), Integer16BitsColorDepthID.id())); KoHistogramProducerFactoryRegistry::instance()->add( new KoBasicHistogramProducerFactory (KoID("YCBCRF32HISTO", i18n("YCbCr/F32 Histogram")), YCbCrAColorModelID.id(), Float32BitsColorDepthID.id())); // Add profile alias for default profile from lcms1 registry->addProfileAlias("sRGB built-in - (lcms internal)", "sRGB built-in"); registry->addProfileAlias("gray built-in - (lcms internal)", "gray built-in"); registry->addProfileAlias("Lab identity built-in - (lcms internal)", "Lab identity built-in"); registry->addProfileAlias("XYZ built-in - (lcms internal)", "XYZ identity built-in"); } #include diff --git a/plugins/color/lcms2engine/tests/TestColorSpaceRegistry.cpp b/plugins/color/lcms2engine/tests/TestColorSpaceRegistry.cpp index 088cd641b8..34186eca8a 100644 --- a/plugins/color/lcms2engine/tests/TestColorSpaceRegistry.cpp +++ b/plugins/color/lcms2engine/tests/TestColorSpaceRegistry.cpp @@ -1,91 +1,91 @@ #include "TestColorSpaceRegistry.h" #include #include "KoColorSpaceRegistry.h" #include "KoColorSpace.h" #include "RgbU8ColorSpace.h" #include "RgbU16ColorSpace.h" #include "LabColorSpace.h" #include "sdk/tests/kistest.h" void TestColorSpaceRegistry::testConstruction() { KoColorSpaceRegistry *instance = KoColorSpaceRegistry::instance(); Q_ASSERT(instance); } void TestColorSpaceRegistry::testRgbU8() { const QString colorSpaceId = KoColorSpaceRegistry::instance()->colorSpaceId(RGBAColorModelID, Integer8BitsColorDepthID); const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8(); QVERIFY(colorSpace != 0); const KoColorProfile *profile = colorSpace->profile(); QVERIFY(profile != 0); QCOMPARE(profile->name(), KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(colorSpaceId)); cmsHPROFILE lcmsProfile = cmsCreate_sRGBProfile(); QString testProfileName = "TestRGBU8ProfileName"; cmsWriteTag(lcmsProfile, cmsSigProfileDescriptionTag, testProfileName.toLatin1().constData()); cmsWriteTag(lcmsProfile, cmsSigDeviceModelDescTag, testProfileName.toLatin1().constData()); cmsWriteTag(lcmsProfile, cmsSigDeviceMfgDescTag, ""); } void TestColorSpaceRegistry::testRgbU16() { const QString colorSpaceId = KoColorSpaceRegistry::instance()->colorSpaceId(RGBAColorModelID, Integer16BitsColorDepthID); const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb16(); QVERIFY(colorSpace != 0); const KoColorProfile *profile = colorSpace->profile(); QVERIFY(profile != 0); QCOMPARE(profile->name(), KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(colorSpaceId)); cmsHPROFILE lcmsProfile = cmsCreate_sRGBProfile(); QString testProfileName = "TestRGBU16ProfileName"; cmsWriteTag(lcmsProfile, cmsSigProfileDescriptionTag, testProfileName.toLatin1().constData()); cmsWriteTag(lcmsProfile, cmsSigDeviceModelDescTag, testProfileName.toLatin1().constData()); cmsWriteTag(lcmsProfile, cmsSigDeviceMfgDescTag, ""); } void TestColorSpaceRegistry::testLab() { const QString colorSpaceId = KoColorSpaceRegistry::instance()->colorSpaceId(LABAColorModelID, Integer16BitsColorDepthID); const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->lab16(); QVERIFY(colorSpace != 0); const KoColorProfile *profile = colorSpace->profile(); QVERIFY(profile != 0); QCOMPARE(profile->name(), KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(colorSpaceId)); cmsCIExyY whitepoint; whitepoint.x = 0.33; whitepoint.y = 0.33; whitepoint.Y = 1.0; - cmsHPROFILE lcmsProfile = cmsCreateLab2Profile(&whitepoint); + cmsHPROFILE lcmsProfile = cmsCreateLab4Profile(&whitepoint); QString testProfileName = "TestLabProfileName"; cmsWriteTag(lcmsProfile, cmsSigProfileDescriptionTag, testProfileName.toLatin1().constData()); cmsWriteTag(lcmsProfile, cmsSigDeviceModelDescTag, testProfileName.toLatin1().constData()); cmsWriteTag(lcmsProfile, cmsSigDeviceMfgDescTag, ""); } KISTEST_MAIN(TestColorSpaceRegistry)