diff --git a/libs/pigment/KoColorSpaceMaths.h b/libs/pigment/KoColorSpaceMaths.h index 09f22b899f..3feed870c8 100644 --- a/libs/pigment/KoColorSpaceMaths.h +++ b/libs/pigment/KoColorSpaceMaths.h @@ -1,829 +1,864 @@ /* * Copyright (c) 2006,2007,2010 Cyrille Berger #include #include "kritapigment_export.h" #include #include "KoChannelInfo.h" #include "KoLut.h" #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) */ template class KoColorSpaceMathsTraits { public: }; template<> class KRITAPIGMENT_EXPORT KoColorSpaceMathsTraits { public: typedef qint32 compositetype; static const quint8 zeroValue = 0; static const quint8 unitValue = 0x00FF; static const quint8 halfValue = 0x00FF / 2; static const quint8 max = 0x00FF; static const quint8 min = 0; static const quint8 epsilon = 1; static const qint8 bits = 8; static const KoChannelInfo::enumChannelValueType channelValueType; }; template<> class KRITAPIGMENT_EXPORT KoColorSpaceMathsTraits { public: typedef qint64 compositetype; static const quint16 zeroValue = 0; static const quint16 unitValue = 0xFFFF; static const quint16 halfValue = 0xFFFF / 2; static const quint16 max = 0xFFFF; static const quint16 min = 0; static const quint16 epsilon = 1; static const qint8 bits = 16; static const KoChannelInfo::enumChannelValueType channelValueType; }; template<> class KRITAPIGMENT_EXPORT KoColorSpaceMathsTraits { public: typedef qint64 compositetype; static const qint16 zeroValue = 0; static const qint16 unitValue = 32767; static const qint16 halfValue = 32767 / 2; static const qint16 max = 32767; static const qint16 min = -32768; static const qint16 epsilon = 1; static const qint8 bits = 16; static const KoChannelInfo::enumChannelValueType channelValueType; }; template<> class KRITAPIGMENT_EXPORT KoColorSpaceMathsTraits { public: typedef qint64 compositetype; static const quint32 zeroValue = 0; static const quint32 unitValue = 0xFFFFFFFF; static const quint32 halfValue = 0xFFFFFFFF / 2; static const quint32 max = 0xFFFFFFFF; static const quint32 min = 0; static const quint32 epsilon = 1; static const qint8 bits = 32; static const KoChannelInfo::enumChannelValueType channelValueType; }; #include #ifdef HAVE_OPENEXR #include template<> class KRITAPIGMENT_EXPORT KoColorSpaceMathsTraits { public: typedef double compositetype; static const half zeroValue; static const half unitValue; static const half halfValue; static const half max; static const half min; static const half epsilon; static const qint8 bits = 16; static const KoChannelInfo::enumChannelValueType channelValueType; }; #endif template<> class KRITAPIGMENT_EXPORT KoColorSpaceMathsTraits { public: typedef double compositetype; static const float zeroValue; static const float unitValue; static const float halfValue; static const float max; static const float min; static const float epsilon; static const qint8 bits = 32; static const KoChannelInfo::enumChannelValueType channelValueType; }; template<> class KRITAPIGMENT_EXPORT KoColorSpaceMathsTraits { public: typedef double compositetype; static const double zeroValue; static const double unitValue; static const double halfValue; static const double max; static const double min; static const double epsilon; static const qint8 bits = 64; static const KoChannelInfo::enumChannelValueType channelValueType; }; #ifdef Q_CC_MSVC // MSVC do not have lrint const double _double2fixmagic = 68719476736.0*1.5; const qint32 _shiftamt = 16; //16.16 fixed point representation, #if Q_BYTE_ORDER == Q_BIG_ENDIAN #define iexp_ 0 #define iman_ 1 #else #define iexp_ 1 #define iman_ 0 #endif //BigEndian_ inline int float2int(double val) { val = val + _double2fixmagic; return ((int*)&val)[iman_] >> _shiftamt; } inline int float2int(float val) { return float2int((double)val); } #else inline int float2int(float x) { return lrintf(x); } inline int float2int(double x) { return lrint(x); } #endif 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; } + inline static dst_compositetype modulus(_T a, _Tdst b) { + return (dst_compositetype(a) - floor(dst_compositetype(a)/((b != (KoColorSpaceMathsTraits<_T>::zeroValue - traits::epsilon) ? b : KoColorSpaceMathsTraits<_T>::zeroValue) + traits::epsilon))*(b + traits::epsilon)); + } + + inline static dst_compositetype xor(_T a, _Tdst b) { + return (int (a * std::numeric_limits::max() - traits::epsilon) ^ int (b * std::numeric_limits::max() - traits::epsilon)); + } + + inline static dst_compositetype and(_T a, _Tdst b) { + return (int (a * std::numeric_limits::max() - traits::epsilon) & int (b * std::numeric_limits::max() - traits::epsilon)); + } + + inline static dst_compositetype or(_T a, _Tdst b) { + return (int (a * std::numeric_limits::max() - traits::epsilon) | int (b * std::numeric_limits::max() - traits::epsilon)); + } + /** * 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 typename KoColorSpaceMathsTraits::compositetype + xor(T a, T b) { return KoColorSpaceMaths::xor(a, b); } + + template + inline typename KoColorSpaceMathsTraits::compositetype + and(T a, T b) { return KoColorSpaceMaths::and(a, b); } + + template + inline typename KoColorSpaceMathsTraits::compositetype + or(T a, T b) { return KoColorSpaceMaths::or(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); } + + template + inline T epsilon() { return KoColorSpaceMathsTraits::epsilon; } + + template + inline typename KoColorSpaceMathsTraits::compositetype + mod(T a, T b) { return KoColorSpaceMaths::modulus(a, b); } } 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/KoCompositeOp.cpp b/libs/pigment/KoCompositeOp.cpp index ab9a599f9b..7f39acc81c 100644 --- a/libs/pigment/KoCompositeOp.cpp +++ b/libs/pigment/KoCompositeOp.cpp @@ -1,189 +1,191 @@ /* * Copyright (c) 2005 Adrian Page * * 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 "KoCompositeOp.h" #include #include #include #include "KoColorSpace.h" #include "KoColorSpaceMaths.h" QString KoCompositeOp::categoryColor() { return i18n("Color"); } QString KoCompositeOp::categoryArithmetic() { return i18n("Arithmetic"); } +QString KoCompositeOp::categoryBinary() { return i18n("Binary"); } +QString KoCompositeOp::categoryModulo() { return i18n("Modulo"); } QString KoCompositeOp::categoryNegative() { return i18n("Negative"); } QString KoCompositeOp::categoryLight() { return i18n("Lighten"); } QString KoCompositeOp::categoryDark() { return i18n("Darken"); } QString KoCompositeOp::categoryHSY() { return i18n("HSY"); } QString KoCompositeOp::categoryHSI() { return i18n("HSI"); } QString KoCompositeOp::categoryHSL() { return i18n("HSL"); } QString KoCompositeOp::categoryHSV() { return i18n("HSV"); } QString KoCompositeOp::categoryMix() { return i18n("Mix"); } QString KoCompositeOp::categoryMisc() { return i18n("Misc"); } -QString KoCompositeOp::categoryQuadratic() { return i18n("Quadratic"); } +QString KoCompositeOp::categoryQuadratic() { return i18n("Quadratic"); } KoCompositeOp::ParameterInfo::ParameterInfo() : opacity(1.0f), flow(1.0f), lastOpacity(&opacity) { } KoCompositeOp::ParameterInfo::ParameterInfo(const ParameterInfo &rhs) { copy(rhs); } KoCompositeOp::ParameterInfo& KoCompositeOp::ParameterInfo::operator=(const ParameterInfo &rhs) { copy(rhs); return *this; } void KoCompositeOp::ParameterInfo::setOpacityAndAverage(float _opacity, float _averageOpacity) { if (qFuzzyCompare(_opacity, _averageOpacity)) { opacity = _opacity; lastOpacity = &opacity; } else { opacity = _opacity; _lastOpacityData = _averageOpacity; lastOpacity = &_lastOpacityData; } } void KoCompositeOp::ParameterInfo::copy(const ParameterInfo &rhs) { dstRowStart = rhs.dstRowStart; dstRowStride = rhs.dstRowStride; srcRowStart = rhs.srcRowStart; srcRowStride = rhs.srcRowStride; maskRowStart = rhs.maskRowStart; maskRowStride = rhs.maskRowStride; rows = rhs.rows; cols = rhs.cols; opacity = rhs.opacity; flow = rhs.flow; _lastOpacityData = rhs._lastOpacityData; channelFlags = rhs.channelFlags; lastOpacity = rhs.lastOpacity == &rhs.opacity ? &opacity : &_lastOpacityData; } void KoCompositeOp::ParameterInfo::updateOpacityAndAverage(float value) { const float exponent = 0.1; opacity = value; if (*lastOpacity < opacity) { lastOpacity = &opacity; } else { _lastOpacityData = exponent * opacity + (1.0 - exponent) * (*lastOpacity); lastOpacity = &_lastOpacityData; } } struct Q_DECL_HIDDEN KoCompositeOp::Private { const KoColorSpace * colorSpace; QString id; QString description; QString category; QBitArray defaultChannelFlags; }; KoCompositeOp::KoCompositeOp() : d(new Private) { } KoCompositeOp::~KoCompositeOp() { delete d; } KoCompositeOp::KoCompositeOp(const KoColorSpace * cs, const QString& id, const QString& description, const QString & category) : d(new Private) { d->colorSpace = cs; d->id = id; d->description = description; d->category = category; if (d->category.isEmpty()) { d->category = categoryMisc(); } } void KoCompositeOp::composite(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, quint8 opacity, const QBitArray& channelFlags) const { KoCompositeOp::ParameterInfo params; params.dstRowStart = dstRowStart; params.dstRowStride = dstRowStride; params.srcRowStart = srcRowStart; params.srcRowStride = srcRowStride; params.maskRowStart = maskRowStart; params.maskRowStride = maskRowStride; params.rows = rows; params.cols = numColumns; params.opacity = float(opacity) / 255.0f; params.flow = 1.0f; params.channelFlags = channelFlags; composite(params); } void KoCompositeOp::composite(const KoCompositeOp::ParameterInfo& params) const { using namespace Arithmetic; composite(params.dstRowStart , params.dstRowStride , params.srcRowStart , params.srcRowStride , params.maskRowStart , params.maskRowStride, params.rows , params.cols , scale(params.opacity), params.channelFlags ); } QString KoCompositeOp::category() const { return d->category; } QString KoCompositeOp::id() const { return d->id; } QString KoCompositeOp::description() const { return d->description; } const KoColorSpace * KoCompositeOp::colorSpace() const { return d->colorSpace; } diff --git a/libs/pigment/KoCompositeOp.h b/libs/pigment/KoCompositeOp.h index da2bc6996d..d3d8b41a89 100644 --- a/libs/pigment/KoCompositeOp.h +++ b/libs/pigment/KoCompositeOp.h @@ -1,149 +1,151 @@ /* * Copyright (c) 2005 Adrian Page * Copyright (c) 2011 Silvio Heinrich * * 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 KOCOMPOSITEOP_H #define KOCOMPOSITEOP_H #include #include #include #include #include #include "kritapigment_export.h" class KoColorSpace; class KoColorSpace; /** * Base for colorspace-specific blending modes. */ class KRITAPIGMENT_EXPORT KoCompositeOp { public: static QString categoryColor(); static QString categoryArithmetic(); + static QString categoryBinary(); + static QString categoryModulo(); static QString categoryNegative(); static QString categoryLight(); static QString categoryDark(); static QString categoryHSY(); static QString categoryHSI(); static QString categoryHSL(); static QString categoryHSV(); static QString categoryMix(); - static QString categoryMisc(); + static QString categoryMisc(); static QString categoryQuadratic(); struct KRITAPIGMENT_EXPORT ParameterInfo { ParameterInfo(); ParameterInfo(const ParameterInfo &rhs); ParameterInfo& operator=(const ParameterInfo &rhs); quint8* dstRowStart; qint32 dstRowStride; const quint8* srcRowStart; qint32 srcRowStride; const quint8* maskRowStart; qint32 maskRowStride; qint32 rows; qint32 cols; float opacity; float flow; float _lastOpacityData; float* lastOpacity; QBitArray channelFlags; void setOpacityAndAverage(float _opacity, float _averageOpacity); void updateOpacityAndAverage(float value); private: inline void copy(const ParameterInfo &rhs); }; public: /** * @param cs a pointer to the color space that can be used with this composite op * @param id the identifier for this composite op (not user visible) * @param description a user visible string describing this composite operation * @param category the name of the category where to put that composite op when displayed * @param userVisible define whether or not that composite op should be visible in a user * interface */ KoCompositeOp(const KoColorSpace * cs, const QString& id, const QString& description, const QString & category = KoCompositeOp::categoryMisc()); virtual ~KoCompositeOp(); /** * @return the identifier of this composite op */ QString id() const; /** * @return the user visible string for this composite op */ QString description() const; /** * @return the color space that can use and own this composite op */ const KoColorSpace * colorSpace() const; /** * @return the category associated with the composite op */ QString category() const; // WARNING: A derived class needs to overwrite at least one // of the following virtual methods or a call to // composite(...) will lead to an endless recursion/stack overflow /** * @param dstRowStart pointer to the start of the byte array we will composite the source on * @param dstRowStride length of the rows of the block of destination pixels in bytes * @param srcRowStart pointer to the start of the byte array we will mix with dest * @param srcRowStride length of the rows of the block of src in bytes * pixels (may be different from the rowstride of the dst pixels, * in which case the smaller value is used). If srcRowStride is null * it is assumed that the source is a constant color. * @param maskRowStart start of the byte mask that determines whether and if so, then how much of src is used for blending * @param maskRowStride length of the mask scanlines in bytes * @param rows number of scanlines to blend * @param numColumns length of the row of pixels in pixels * @param opacity transparency with which to blend * @param channelFlags a bit array that determines which channels should be processed (channels are in the order of the channels in the colorspace) */ virtual void composite(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, quint8 opacity, const QBitArray& channelFlags=QBitArray()) const; /** * Same as previous, but uses a parameter structure */ virtual void composite(const ParameterInfo& params) const; private: KoCompositeOp(); struct Private; Private* const d; }; #endif // KOCOMPOSITEOP_H diff --git a/libs/pigment/KoCompositeOpRegistry.cpp b/libs/pigment/KoCompositeOpRegistry.cpp index b52ba982f0..4fe5575fff 100644 --- a/libs/pigment/KoCompositeOpRegistry.cpp +++ b/libs/pigment/KoCompositeOpRegistry.cpp @@ -1,222 +1,269 @@ /* * Copyright (c) 2005 Adrian Page * * 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 "KoCompositeOpRegistry.h" #include #include #include #include #include "KoCompositeOp.h" #include "KoColorSpace.h" Q_GLOBAL_STATIC(KoCompositeOpRegistry, registry) KoCompositeOpRegistry::KoCompositeOpRegistry() { m_categories << KoID("arithmetic", i18n("Arithmetic")) + << KoID("binary" , i18n("Binary")) << KoID("dark" , i18n("Darken")) << KoID("light" , i18n("Lighten")) + << KoID("modulo" , i18n("Modulo")) << KoID("negative" , i18n("Negative")) << KoID("mix" , i18n("Mix")) << KoID("misc" , i18n("Misc")) << KoID("hsy" , i18n("HSY")) << KoID("hsi" , i18n("HSI")) << KoID("hsl" , i18n("HSL")) << KoID("hsv" , i18n("HSV")) << KoID("quadratic" , i18n("Quadratic")); m_map.insert(m_categories[0], KoID(COMPOSITE_ADD , i18n("Addition"))); m_map.insert(m_categories[0], KoID(COMPOSITE_SUBTRACT , i18n("Subtract"))); m_map.insert(m_categories[0], KoID(COMPOSITE_MULT , i18n("Multiply"))); m_map.insert(m_categories[0], KoID(COMPOSITE_DIVIDE , i18n("Divide"))); m_map.insert(m_categories[0], KoID(COMPOSITE_INVERSE_SUBTRACT, i18n("Inverse Subtract"))); + + m_map.insert(m_categories[1], KoID(COMPOSITE_XOR , i18n("XOR"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_OR , i18n("OR"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_AND , i18n("AND"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_NAND , i18n("NAND"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_NOR , i18n("NOR"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_XNOR , i18n("XNOR"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_IMPLICATION , i18n("IMPLICATION"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_NOT_IMPLICATION , i18n("NOT IMPLICATION"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_CONVERSE , i18n("CONVERSE"))); + m_map.insert(m_categories[1], KoID(COMPOSITE_NOT_CONVERSE , i18n("NOT CONVERSE"))); + + m_map.insert(m_categories[2], KoID(COMPOSITE_BURN , i18n("Burn"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_BURN_LOGARITHMIC , i18n("Burn - Logarithmic"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_LINEAR_BURN, i18n("Linear Burn"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_DARKEN , i18n("Darken"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_GAMMA_DARK , i18n("Gamma Dark"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_DARKER_COLOR , i18n("Darker Color"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_SHADE_IFS_ILLUSIONS, i18n("Shade (IFS Illusions)"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_FOG_DARKEN_IFS_ILLUSIONS, i18n("Fog Darken (IFS Illusions)"))); + m_map.insert(m_categories[2], KoID(COMPOSITE_EASY_BURN , i18n("Easy Burn"))); + + m_map.insert(m_categories[3], KoID(COMPOSITE_DODGE , i18n("Color Dodge"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_DODGE_LOGARITHMIC , i18n("Color Dodge - Logarithmic"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_LIGHTEN , i18n("Lighten"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_LINEAR_LIGHT, i18n("Linear Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SCREEN , i18n("Screen"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_PIN_LIGHT , i18n("Pin Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_VIVID_LIGHT , i18n("Vivid Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_FLAT_LIGHT , i18n("Flat Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_HARD_LIGHT , i18n("Hard Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SOFT_LIGHT_IFS_ILLUSIONS, i18n("Soft Light (IFS Illusions)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SOFT_LIGHT_PEGTOP_DELPHI, i18n("Soft Light (Pegtop-Delphi)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SOFT_LIGHT_PHOTOSHOP, i18n("Soft Light (Photoshop)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SOFT_LIGHT_SVG, i18n("Soft Light (SVG)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_GAMMA_ILLUMINATION , i18n("Gamma Illumination"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_LIGHTER_COLOR , i18n("Lighter Color"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_PNORM_A , i18n("P-Norm A"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_PNORM_B , i18n("P-Norm B"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_SUPER_LIGHT , i18n("Super Light"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_TINT_IFS_ILLUSIONS, i18n("Tint (IFS Illusions)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_FOG_LIGHTEN_IFS_ILLUSIONS, i18n("Fog Lighten (IFS Illusions)"))); + m_map.insert(m_categories[3], KoID(COMPOSITE_EASY_DODGE , i18n("Easy Dodge"))); + + m_map.insert(m_categories[4], KoID(COMPOSITE_MOD , i18n("Modulo"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_MOD_CON , i18n("Modulo - Continuous"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_DIVISIVE_MOD , i18n("Divisive Modulo"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_DIVISIVE_MOD_CON , i18n("Divisive Modulo - Continuous"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_MODULO_SHIFT , i18n("Modulo Shift"))); + m_map.insert(m_categories[4], KoID(COMPOSITE_MODULO_SHIFT_CON , i18n("Modulo Shift - Continuous"))); + + m_map.insert(m_categories[5], KoID(COMPOSITE_DIFF , i18n("Difference"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_EQUIVALENCE , i18n("Equivalence"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_ADDITIVE_SUBTRACTIVE , i18n("Additive Subtractive"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_EXCLUSION , i18n("Exclusion"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent"))); + m_map.insert(m_categories[5], KoID(COMPOSITE_NEGATION , i18n("Negation"))); + + m_map.insert(m_categories[6], KoID(COMPOSITE_OVER , i18n("Normal"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_BEHIND , i18n("Behind"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_GREATER , i18n("Greater"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_OVERLAY , i18n("Overlay"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_ERASE , i18n("Erase"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_ALPHA_DARKEN , i18n("Alpha Darken"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_HARD_MIX , i18n("Hard Mix"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_HARD_MIX_PHOTOSHOP, i18n("Hard Mix (Photoshop)"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_GRAIN_MERGE , i18n("Grain Merge"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_GRAIN_EXTRACT , i18n("Grain Extract"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PARALLEL , i18n("Parallel"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_ALLANON , i18n("Allanon"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_GEOMETRIC_MEAN , i18n("Geometric Mean"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_DESTINATION_ATOP, i18n("Destination Atop"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_DESTINATION_IN , i18n("Destination In"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_HARD_OVERLAY , i18n("Hard Overlay"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_INTERPOLATION , i18n("Interpolation"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_INTERPOLATIONB , i18n("Interpolation - 2X"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PENUMBRAA , i18n("Penumbra A"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PENUMBRAB , i18n("Penumbra B"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PENUMBRAC , i18n("Penumbra C"))); + m_map.insert(m_categories[6], KoID(COMPOSITE_PENUMBRAD , i18n("Penumbra D"))); + + m_map.insert(m_categories[7], KoID(COMPOSITE_BUMPMAP , i18n("Bumpmap"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COMBINE_NORMAL, i18n("Combine Normal Map"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_DISSOLVE , i18n("Dissolve"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COPY_RED , i18n("Copy Red"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COPY_GREEN, i18n("Copy Green"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COPY_BLUE , i18n("Copy Blue"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_COPY , i18n("Copy"))); + m_map.insert(m_categories[7], KoID(COMPOSITE_TANGENT_NORMALMAP, i18n("Tangent Normalmap"))); + + m_map.insert(m_categories[8], KoID(COMPOSITE_COLOR , i18n("Color"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_HUE , i18n("Hue"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_SATURATION , i18n("Saturation"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_LUMINIZE , i18n("Luminosity"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_SATURATION, i18n("Decrease Saturation"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_INC_SATURATION, i18n("Increase Saturation"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_LUMINOSITY, i18n("Decrease Luminosity"))); + m_map.insert(m_categories[8], KoID(COMPOSITE_INC_LUMINOSITY, i18n("Increase Luminosity"))); + + m_map.insert(m_categories[9], KoID(COMPOSITE_COLOR_HSI , i18n("Color HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_HUE_HSI , i18n("Hue HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_SATURATION_HSI , i18n("Saturation HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_INTENSITY , i18n("Intensity"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_SATURATION_HSI, i18n("Decrease Saturation HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_INC_SATURATION_HSI, i18n("Increase Saturation HSI"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_INTENSITY , i18n("Decrease Intensity"))); + m_map.insert(m_categories[9], KoID(COMPOSITE_INC_INTENSITY , i18n("Increase Intensity"))); + + m_map.insert(m_categories[10], KoID(COMPOSITE_COLOR_HSL , i18n("Color HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_HUE_HSL , i18n("Hue HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_SATURATION_HSL , i18n("Saturation HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_LIGHTNESS , i18n("Lightness"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_DEC_SATURATION_HSL, i18n("Decrease Saturation HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_INC_SATURATION_HSL, i18n("Increase Saturation HSL"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_DEC_LIGHTNESS , i18n("Decrease Lightness"))); + m_map.insert(m_categories[10], KoID(COMPOSITE_INC_LIGHTNESS , i18n("Increase Lightness"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_BURN , i18n("Burn"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_LINEAR_BURN, i18n("Linear Burn"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_DARKEN , i18n("Darken"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_GAMMA_DARK , i18n("Gamma Dark"))); - m_map.insert(m_categories[1], KoID(COMPOSITE_DARKER_COLOR , i18n("Darker Color"))); - - m_map.insert(m_categories[2], KoID(COMPOSITE_DODGE , i18n("Color Dodge"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_LIGHTEN , i18n("Lighten"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_LINEAR_LIGHT, i18n("Linear Light"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_SCREEN , i18n("Screen"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_PIN_LIGHT , i18n("Pin Light"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_VIVID_LIGHT , i18n("Vivid Light"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_HARD_LIGHT , i18n("Hard Light"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_SOFT_LIGHT_PHOTOSHOP, i18n("Soft Light (Photoshop)"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_SOFT_LIGHT_SVG, i18n("Soft Light (SVG)"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light"))); - m_map.insert(m_categories[2], KoID(COMPOSITE_LIGHTER_COLOR , i18n("Lighter Color"))); - - m_map.insert(m_categories[3], KoID(COMPOSITE_DIFF , i18n("Difference"))); - m_map.insert(m_categories[3], KoID(COMPOSITE_EQUIVALENCE , i18n("Equivalence"))); - m_map.insert(m_categories[3], KoID(COMPOSITE_ADDITIVE_SUBTRACTIVE, i18n("Additive Subtractive"))); - m_map.insert(m_categories[3], KoID(COMPOSITE_EXCLUSION , i18n("Exclusion"))); - m_map.insert(m_categories[3], KoID(COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent"))); - - m_map.insert(m_categories[4], KoID(COMPOSITE_OVER , i18n("Normal"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_BEHIND , i18n("Behind"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_GREATER , i18n("Greater"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_OVERLAY , i18n("Overlay"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_ERASE , i18n("Erase"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_ALPHA_DARKEN , i18n("Alpha Darken"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_HARD_MIX , i18n("Hard Mix"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_HARD_MIX_PHOTOSHOP, i18n("Hard Mix (Photoshop)"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_MERGE , i18n("Grain Merge"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_EXTRACT , i18n("Grain Extract"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_PARALLEL , i18n("Parallel"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_ALLANON , i18n("Allanon"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_GEOMETRIC_MEAN , i18n("Geometric Mean"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_DESTINATION_ATOP, i18n("Destination Atop"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_DESTINATION_IN , i18n("Destination In"))); - m_map.insert(m_categories[4], KoID(COMPOSITE_HARD_OVERLAY , i18n("Hard Overlay"))); - - m_map.insert(m_categories[5], KoID(COMPOSITE_BUMPMAP , i18n("Bumpmap"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COMBINE_NORMAL, i18n("Combine Normal Map"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_DISSOLVE , i18n("Dissolve"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COPY_RED , i18n("Copy Red"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COPY_GREEN, i18n("Copy Green"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COPY_BLUE , i18n("Copy Blue"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_COPY , i18n("Copy"))); - m_map.insert(m_categories[5], KoID(COMPOSITE_TANGENT_NORMALMAP, i18n("Tangent Normalmap"))); - - m_map.insert(m_categories[6], KoID(COMPOSITE_COLOR , i18n("Color"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_HUE , i18n("Hue"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_SATURATION , i18n("Saturation"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_LUMINIZE , i18n("Luminosity"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_DEC_SATURATION, i18n("Decrease Saturation"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_INC_SATURATION, i18n("Increase Saturation"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_DEC_LUMINOSITY, i18n("Decrease Luminosity"))); - m_map.insert(m_categories[6], KoID(COMPOSITE_INC_LUMINOSITY, i18n("Increase Luminosity"))); - - m_map.insert(m_categories[7], KoID(COMPOSITE_COLOR_HSI , i18n("Color HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_HUE_HSI , i18n("Hue HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_SATURATION_HSI , i18n("Saturation HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_INTENSITY , i18n("Intensity"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_DEC_SATURATION_HSI, i18n("Decrease Saturation HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_INC_SATURATION_HSI, i18n("Increase Saturation HSI"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_DEC_INTENSITY , i18n("Decrease Intensity"))); - m_map.insert(m_categories[7], KoID(COMPOSITE_INC_INTENSITY , i18n("Increase Intensity"))); - - m_map.insert(m_categories[8], KoID(COMPOSITE_COLOR_HSL , i18n("Color HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_HUE_HSL , i18n("Hue HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_SATURATION_HSL , i18n("Saturation HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_LIGHTNESS , i18n("Lightness"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_SATURATION_HSL, i18n("Decrease Saturation HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_INC_SATURATION_HSL, i18n("Increase Saturation HSL"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_LIGHTNESS , i18n("Decrease Lightness"))); - m_map.insert(m_categories[8], KoID(COMPOSITE_INC_LIGHTNESS , i18n("Increase Lightness"))); - - m_map.insert(m_categories[9], KoID(COMPOSITE_COLOR_HSV , i18n("Color HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_HUE_HSV , i18n("Hue HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_SATURATION_HSV , i18n("Saturation HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_VALUE , i18nc("HSV Value", "Value"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_SATURATION_HSV, i18n("Decrease Saturation HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_INC_SATURATION_HSV, i18n("Increase Saturation HSV"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_VALUE , i18n("Decrease Value"))); - m_map.insert(m_categories[9], KoID(COMPOSITE_INC_VALUE , i18n("Increase Value"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_COLOR_HSV , i18n("Color HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_HUE_HSV , i18n("Hue HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_SATURATION_HSV , i18n("Saturation HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_VALUE , i18nc("HSV Value", "Value"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_DEC_SATURATION_HSV, i18n("Decrease Saturation HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_INC_SATURATION_HSV, i18n("Increase Saturation HSV"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_DEC_VALUE , i18n("Decrease Value"))); + m_map.insert(m_categories[11], KoID(COMPOSITE_INC_VALUE , i18n("Increase Value"))); - m_map.insert(m_categories[10], KoID(COMPOSITE_REFLECT , i18n("Reflect"))); - m_map.insert(m_categories[10], KoID(COMPOSITE_GLOW , i18n("Glow"))); - m_map.insert(m_categories[10], KoID(COMPOSITE_FREEZE , i18n("Freeze"))); - m_map.insert(m_categories[10], KoID(COMPOSITE_HEAT , i18n("Heat"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_REFLECT , i18n("Reflect"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_GLOW , i18n("Glow"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_FREEZE , i18n("Freeze"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_HEAT , i18n("Heat"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_GLEAT , i18n("Glow-Heat"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_HELOW , i18n("Heat-Glow"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_REEZE , i18n("Reflect-Freeze"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_FRECT , i18n("Freeze-Reflect"))); + m_map.insert(m_categories[12], KoID(COMPOSITE_FHYRD , i18n("Heat-Glow & Freeze-Reflect Hybrid"))); } const KoCompositeOpRegistry& KoCompositeOpRegistry::instance() { return *registry; } KoID KoCompositeOpRegistry::getDefaultCompositeOp() const { return KoID(COMPOSITE_OVER, i18n("Normal")); } KoID KoCompositeOpRegistry::getKoID(const QString& compositeOpID) const { KoIDMap::const_iterator itr = std::find(m_map.begin(), m_map.end(), KoID(compositeOpID)); return (itr != m_map.end()) ? *itr : KoID(); } KoCompositeOpRegistry::KoIDMap KoCompositeOpRegistry::getCompositeOps() const { return m_map; } KoCompositeOpRegistry::KoIDList KoCompositeOpRegistry::getCategories() const { return m_categories; } KoCompositeOpRegistry::KoIDList KoCompositeOpRegistry::getCompositeOps(const KoID& category, const KoColorSpace* colorSpace) const { qint32 num = m_map.count(category); KoIDMap::const_iterator beg = m_map.find(category); KoIDMap::const_iterator end = beg + num; KoIDList list; list.reserve(num); if(colorSpace) { for(; beg!=end; ++beg){ if(colorSpace->hasCompositeOp(beg->id())) list.push_back(*beg); } } else { for(; beg!=end; ++beg) list.push_back(*beg); } return list; } KoCompositeOpRegistry::KoIDList KoCompositeOpRegistry::getCompositeOps(const KoColorSpace* colorSpace) const { KoIDMap::const_iterator beg = m_map.begin(); KoIDMap::const_iterator end = m_map.end(); KoIDList list; list.reserve(m_map.size()); if(colorSpace) { for(; beg!=end; ++beg){ if(colorSpace->hasCompositeOp(beg->id())) list.push_back(*beg); } } else { for(; beg!=end; ++beg) list.push_back(*beg); } return list; } bool KoCompositeOpRegistry::colorSpaceHasCompositeOp(const KoColorSpace* colorSpace, const KoID& compositeOp) const { return colorSpace ? colorSpace->hasCompositeOp(compositeOp.id()) : false; } diff --git a/libs/pigment/KoCompositeOpRegistry.h b/libs/pigment/KoCompositeOpRegistry.h index bedfb5e43b..58b9641625 100644 --- a/libs/pigment/KoCompositeOpRegistry.h +++ b/libs/pigment/KoCompositeOpRegistry.h @@ -1,183 +1,227 @@ /* * Copyright (c) 2005 Adrian Page * Copyright (c) 2011 Silvio Heinrich * * 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 KOCOMPOSITEOPREGISTRY_H #define KOCOMPOSITEOPREGISTRY_H #include #include #include #include #include "kritapigment_export.h" class KoColorSpace; #include // TODO : convert this data blob into a modern design with an enum class. // This will reduce the need for runtime string comparisons. const QString COMPOSITE_OVER = "normal"; const QString COMPOSITE_ERASE = "erase"; const QString COMPOSITE_IN = "in"; const QString COMPOSITE_OUT = "out"; const QString COMPOSITE_ALPHA_DARKEN = "alphadarken"; const QString COMPOSITE_DESTINATION_IN = "destination-in"; const QString COMPOSITE_DESTINATION_ATOP = "destination-atop"; const QString COMPOSITE_XOR = "xor"; +const QString COMPOSITE_OR = "or"; +const QString COMPOSITE_AND = "and"; +const QString COMPOSITE_NAND = "nand"; +const QString COMPOSITE_NOR = "nor"; +const QString COMPOSITE_XNOR = "xnor"; +const QString COMPOSITE_IMPLICATION = "implication"; +const QString COMPOSITE_NOT_IMPLICATION = "not_implication"; +const QString COMPOSITE_CONVERSE = "converse"; +const QString COMPOSITE_NOT_CONVERSE = "not_converse"; + const QString COMPOSITE_PLUS = "plus"; const QString COMPOSITE_MINUS = "minus"; const QString COMPOSITE_ADD = "add"; const QString COMPOSITE_SUBTRACT = "subtract"; const QString COMPOSITE_INVERSE_SUBTRACT = "inverse_subtract"; const QString COMPOSITE_DIFF = "diff"; const QString COMPOSITE_MULT = "multiply"; const QString COMPOSITE_DIVIDE = "divide"; const QString COMPOSITE_ARC_TANGENT = "arc_tangent"; const QString COMPOSITE_GEOMETRIC_MEAN = "geometric_mean"; const QString COMPOSITE_ADDITIVE_SUBTRACTIVE = "additive_subtractive"; +const QString COMPOSITE_NEGATION = "negation"; + +const QString COMPOSITE_MOD = "modulo"; +const QString COMPOSITE_MOD_CON = "modulo_continuous"; +const QString COMPOSITE_DIVISIVE_MOD = "divisive_modulo"; +const QString COMPOSITE_DIVISIVE_MOD_CON = "divisive_modulo_continuous"; +const QString COMPOSITE_MODULO_SHIFT = "modulo_shift"; +const QString COMPOSITE_MODULO_SHIFT_CON = "modulo_shift_continuous"; const QString COMPOSITE_EQUIVALENCE = "equivalence"; const QString COMPOSITE_ALLANON = "allanon"; const QString COMPOSITE_PARALLEL = "parallel"; const QString COMPOSITE_GRAIN_MERGE = "grain_merge"; const QString COMPOSITE_GRAIN_EXTRACT = "grain_extract"; const QString COMPOSITE_EXCLUSION = "exclusion"; const QString COMPOSITE_HARD_MIX = "hard mix"; const QString COMPOSITE_HARD_MIX_PHOTOSHOP = "hard_mix_photoshop"; const QString COMPOSITE_OVERLAY = "overlay"; const QString COMPOSITE_BEHIND = "behind"; const QString COMPOSITE_GREATER = "greater"; const QString COMPOSITE_HARD_OVERLAY = "hard overlay"; +const QString COMPOSITE_INTERPOLATION = "interpolation"; +const QString COMPOSITE_INTERPOLATIONB = "interpolation 2x"; +const QString COMPOSITE_PENUMBRAA = "penumbra a"; +const QString COMPOSITE_PENUMBRAB = "penumbra b"; +const QString COMPOSITE_PENUMBRAC = "penumbra c"; +const QString COMPOSITE_PENUMBRAD = "penumbra d"; const QString COMPOSITE_DARKEN = "darken"; const QString COMPOSITE_BURN = "burn";//this is also known as 'color burn'. +const QString COMPOSITE_BURN_LOGARITHMIC = "burn_logarithmic"; const QString COMPOSITE_LINEAR_BURN = "linear_burn"; const QString COMPOSITE_GAMMA_DARK = "gamma_dark"; +const QString COMPOSITE_SHADE_IFS_ILLUSIONS = "shade_ifs_illusions"; +const QString COMPOSITE_FOG_DARKEN_IFS_ILLUSIONS = "fog_darken_ifs_illusions"; +const QString COMPOSITE_EASY_BURN = "easy burn"; const QString COMPOSITE_LIGHTEN = "lighten"; const QString COMPOSITE_DODGE = "dodge"; +const QString COMPOSITE_DODGE_LOGARITHMIC = "dodge_logarithmic"; const QString COMPOSITE_LINEAR_DODGE = "linear_dodge"; const QString COMPOSITE_SCREEN = "screen"; const QString COMPOSITE_HARD_LIGHT = "hard_light"; +const QString COMPOSITE_SOFT_LIGHT_IFS_ILLUSIONS = "soft_light_ifs_illusions"; +const QString COMPOSITE_SOFT_LIGHT_PEGTOP_DELPHI = "soft_light_pegtop_delphi"; const QString COMPOSITE_SOFT_LIGHT_PHOTOSHOP = "soft_light"; const QString COMPOSITE_SOFT_LIGHT_SVG = "soft_light_svg"; const QString COMPOSITE_GAMMA_LIGHT = "gamma_light"; +const QString COMPOSITE_GAMMA_ILLUMINATION = "gamma_illumination"; const QString COMPOSITE_VIVID_LIGHT = "vivid_light"; +const QString COMPOSITE_FLAT_LIGHT = "flat_light"; const QString COMPOSITE_LINEAR_LIGHT = "linear light"; const QString COMPOSITE_PIN_LIGHT = "pin_light"; +const QString COMPOSITE_PNORM_A = "pnorm_a"; +const QString COMPOSITE_PNORM_B = "pnorm_b"; +const QString COMPOSITE_SUPER_LIGHT = "super_light"; +const QString COMPOSITE_TINT_IFS_ILLUSIONS = "tint_ifs_illusions"; +const QString COMPOSITE_FOG_LIGHTEN_IFS_ILLUSIONS = "fog_lighten_ifs_illusions"; +const QString COMPOSITE_EASY_DODGE = "easy dodge"; const QString COMPOSITE_HUE = "hue"; const QString COMPOSITE_COLOR = "color"; const QString COMPOSITE_SATURATION = "saturation"; const QString COMPOSITE_INC_SATURATION = "inc_saturation"; const QString COMPOSITE_DEC_SATURATION = "dec_saturation"; const QString COMPOSITE_LUMINIZE = "luminize"; const QString COMPOSITE_INC_LUMINOSITY = "inc_luminosity"; const QString COMPOSITE_DEC_LUMINOSITY = "dec_luminosity"; const QString COMPOSITE_HUE_HSV = "hue_hsv"; const QString COMPOSITE_COLOR_HSV = "color_hsv"; const QString COMPOSITE_SATURATION_HSV = "saturation_hsv"; const QString COMPOSITE_INC_SATURATION_HSV = "inc_saturation_hsv"; const QString COMPOSITE_DEC_SATURATION_HSV = "dec_saturation_hsv"; const QString COMPOSITE_VALUE = "value"; const QString COMPOSITE_INC_VALUE = "inc_value"; const QString COMPOSITE_DEC_VALUE = "dec_value"; const QString COMPOSITE_HUE_HSL = "hue_hsl"; const QString COMPOSITE_COLOR_HSL = "color_hsl"; const QString COMPOSITE_SATURATION_HSL = "saturation_hsl"; const QString COMPOSITE_INC_SATURATION_HSL = "inc_saturation_hsl"; const QString COMPOSITE_DEC_SATURATION_HSL = "dec_saturation_hsl"; const QString COMPOSITE_LIGHTNESS = "lightness"; const QString COMPOSITE_INC_LIGHTNESS = "inc_lightness"; const QString COMPOSITE_DEC_LIGHTNESS = "dec_lightness"; const QString COMPOSITE_HUE_HSI = "hue_hsi"; const QString COMPOSITE_COLOR_HSI = "color_hsi"; const QString COMPOSITE_SATURATION_HSI = "saturation_hsi"; const QString COMPOSITE_INC_SATURATION_HSI = "inc_saturation_hsi"; const QString COMPOSITE_DEC_SATURATION_HSI = "dec_saturation_hsi"; const QString COMPOSITE_INTENSITY = "intensity"; const QString COMPOSITE_INC_INTENSITY = "inc_intensity"; const QString COMPOSITE_DEC_INTENSITY = "dec_intensity"; const QString COMPOSITE_COPY = "copy"; const QString COMPOSITE_COPY_RED = "copy_red"; const QString COMPOSITE_COPY_GREEN = "copy_green"; const QString COMPOSITE_COPY_BLUE = "copy_blue"; const QString COMPOSITE_TANGENT_NORMALMAP = "tangent_normalmap"; const QString COMPOSITE_COLORIZE = "colorize"; const QString COMPOSITE_BUMPMAP = "bumpmap"; const QString COMPOSITE_COMBINE_NORMAL = "combine_normal"; const QString COMPOSITE_CLEAR = "clear"; const QString COMPOSITE_DISSOLVE = "dissolve"; const QString COMPOSITE_DISPLACE = "displace"; const QString COMPOSITE_NO = "nocomposition"; const QString COMPOSITE_PASS_THROUGH = "pass through"; // XXX: not implemented anywhere yet const QString COMPOSITE_DARKER_COLOR = "darker color"; const QString COMPOSITE_LIGHTER_COLOR = "lighter color"; const QString COMPOSITE_UNDEF = "undefined"; const QString COMPOSITE_REFLECT = "reflect"; const QString COMPOSITE_GLOW = "glow"; const QString COMPOSITE_FREEZE = "freeze"; const QString COMPOSITE_HEAT = "heat"; +const QString COMPOSITE_GLEAT = "glow_heat"; +const QString COMPOSITE_HELOW = "heat_glow"; +const QString COMPOSITE_REEZE = "reflect_freeze"; +const QString COMPOSITE_FRECT = "freeze_reflect"; +const QString COMPOSITE_FHYRD = "heat_glow_freeze_reflect_hybrid"; class KRITAPIGMENT_EXPORT KoCompositeOpRegistry { typedef QMultiMap KoIDMap; typedef QList KoIDList; public: KoCompositeOpRegistry(); static const KoCompositeOpRegistry& instance(); KoID getDefaultCompositeOp() const; KoID getKoID(const QString& compositeOpID) const; KoIDMap getCompositeOps() const; KoIDList getCategories() const; KoIDList getCompositeOps(const KoColorSpace* colorSpace) const; KoIDList getCompositeOps(const KoID& category, const KoColorSpace* colorSpace=0) const; bool colorSpaceHasCompositeOp(const KoColorSpace* colorSpace, const KoID& compositeOp) const; template KoIDList filterCompositeOps(TKoIdIterator begin, TKoIdIterator end, const KoColorSpace* colorSpace, bool removeInvaliOps=true) const { KoIDList list; for(; begin!=end; ++begin){ if( colorSpaceHasCompositeOp(colorSpace, *begin) == removeInvaliOps) list.push_back(*begin); } return list; } private: KoIDList m_categories; KoIDMap m_map; }; #endif // KOCOMPOSITEOPREGISTRY_H diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index 9c2eb96373..a7b2fbbc46 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -1,503 +1,959 @@ /* * Copyright (c) 2011 Silvio Heinrich * * 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 KOCOMPOSITEOP_FUNCTIONS_H_ #define KOCOMPOSITEOP_FUNCTIONS_H_ #include template inline void cfReorientedNormalMapCombine(TReal srcR, TReal srcG, TReal srcB, TReal& dstR, TReal& dstG, TReal& dstB) { // see http://blog.selfshadow.com/publications/blending-in-detail/ by Barre-Brisebois and Hill TReal tx = 2*srcR-1; TReal ty = 2*srcG-1; TReal tz = 2*srcB; TReal ux = -2*dstR+1; TReal uy = -2*dstG+1; TReal uz = 2*dstB-1; TReal k = (tx*ux+ty*uy+tz*uz)/tz; // dot(t,u)/t.z TReal rx = tx*k-ux; TReal ry = ty*k-uy; TReal rz = tz*k-uz; k = 1/sqrt(rx*rx+ry*ry+rz*rz); // normalize result rx *= k; ry *= k; rz *= k; dstR = rx*0.5+0.5; dstG = ry*0.5+0.5; dstB = rz*0.5+0.5; } template inline void cfColor(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { TReal lum = getLightness(dr, dg, db); dr = sr; dg = sg; db = sb; setLightness(dr, dg, db, lum); } template inline void cfLightness(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { setLightness(dr, dg, db, getLightness(sr, sg, sb)); } template inline void cfIncreaseLightness(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { addLightness(dr, dg, db, getLightness(sr, sg, sb)); } template inline void cfDecreaseLightness(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { addLightness(dr, dg, db, getLightness(sr, sg, sb) - TReal(1.0)); } template inline void cfSaturation(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { TReal sat = getSaturation(sr, sg, sb); TReal light = getLightness(dr, dg, db); setSaturation(dr, dg, db, sat); setLightness(dr, dg, db, light); } template inline void cfIncreaseSaturation(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { using namespace Arithmetic; TReal sat = lerp(getSaturation(dr,dg,db), unitValue(), getSaturation(sr,sg,sb)); TReal light = getLightness(dr, dg, db); setSaturation(dr, dg, db, sat); setLightness(dr, dg, db, light); } template inline void cfDecreaseSaturation(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { using namespace Arithmetic; TReal sat = lerp(zeroValue(), getSaturation(dr,dg,db), getSaturation(sr,sg,sb)); TReal light = getLightness(dr, dg, db); setSaturation(dr, dg, db, sat); setLightness(dr, dg, db, light); } template inline void cfHue(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { TReal sat = getSaturation(dr, dg, db); TReal lum = getLightness(dr, dg, db); dr = sr; dg = sg; db = sb; setSaturation(dr, dg, db, sat); setLightness(dr, dg, db, lum); } template inline void cfTangentNormalmap(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { using namespace Arithmetic; TReal half=halfValue(); dr = sr+(dr-half); dg = sg+(dg-half); db = sb+(db-unitValue()); } template inline void cfDarkerColor(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { TReal lum = getLightness(dr, dg, db); TReal lum2 = getLightness(sr, sg, sb); if (lum inline void cfLighterColor(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { TReal lum = getLightness(dr, dg, db); TReal lum2 = getLightness(sr, sg, sb); if (lum>lum2) { sr = dr; sg = dg; sb = db; } else { dr = sr; dg = sg; db = sb; } } template inline T cfColorBurn(T src, T dst) { using namespace Arithmetic; if(dst == unitValue()) return unitValue(); T invDst = inv(dst); if(src < invDst) return zeroValue(); return inv(clamp(div(invDst, src))); } template inline T cfLinearBurn(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; return clamp(composite_type(src) + dst - unitValue()); } template inline T cfColorDodge(T src, T dst) { using namespace Arithmetic; - - if(dst == zeroValue()) - return zeroValue(); + //Fixing Color Dodge to avoid ZX Colors on bright area. + + if(src == unitValue()) + return unitValue(); T invSrc = inv(src); - if(invSrc < dst) + if(invSrc == zeroValue()) return unitValue(); return Arithmetic::clamp(div(dst, invSrc)); } template inline T cfAddition(T src, T dst) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; return Arithmetic::clamp(composite_type(src) + dst); } template inline T cfSubtract(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; return clamp(composite_type(dst) - src); } template inline T cfInverseSubtract(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; return clamp(composite_type(dst) - inv(src)); } template inline T cfExclusion(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; composite_type x = mul(src, dst); return clamp(composite_type(dst) + src - (x + x)); } template inline T cfDivide(T src, T dst) { using namespace Arithmetic; //typedef typename KoColorSpaceMathsTraits::compositetype composite_type; if(src == zeroValue()) return (dst == zeroValue()) ? zeroValue() : unitValue(); return clamp(div(dst, src)); } template inline T cfHardLight(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; composite_type src2 = composite_type(src) + src; if(src > halfValue()) { // screen(src*2.0 - 1.0, dst) src2 -= unitValue(); // src2 is guaranteed to be smaller than unitValue() now return Arithmetic::unionShapeOpacity(T(src2), dst); } // src2 is guaranteed to be smaller than unitValue() due to 'if' return Arithmetic::mul(T(src2), dst); } template inline T cfSoftLightSvg(T src, T dst) { using namespace Arithmetic; qreal fsrc = scale(src); qreal fdst = scale(dst); if(fsrc > 0.5f) { qreal D = (fdst > 0.25f) ? sqrt(fdst) : ((16.0f*fdst - 12.0)*fdst + 4.0f)*fdst; return scale(fdst + (2.0f*fsrc - 1.0f) * (D - fdst)); } return scale(fdst - (1.0f - 2.0f * fsrc) * fdst * (1.0f - fdst)); } template inline T cfSoftLight(T src, T dst) { using namespace Arithmetic; qreal fsrc = scale(src); qreal fdst = scale(dst); if(fsrc > 0.5f) { return scale(fdst + (2.0f * fsrc - 1.0f) * (sqrt(fdst) - fdst)); } return scale(fdst - (1.0f - 2.0f*fsrc) * fdst * (1.0f - fdst)); } template inline T cfVividLight(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; if(src < halfValue()) { if(src == zeroValue()) return (dst == unitValue()) ? unitValue() : zeroValue(); // min(1,max(0,1-(1-dst) / (2*src))) composite_type src2 = composite_type(src) + src; composite_type dsti = inv(dst); return clamp(unitValue() - (dsti * unitValue() / src2)); } if(src == unitValue()) return (dst == zeroValue()) ? zeroValue() : unitValue(); // min(1,max(0, dst / (2*(1-src))) composite_type srci2 = inv(src); srci2 += srci2; return clamp(composite_type(dst) * unitValue() / srci2); } template inline T cfPinLight(T src, T dst) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; // TODO: verify that the formula is correct (the first max would be useless here) // max(0, max(2*src-1, min(dst, 2*src))) composite_type src2 = composite_type(src) + src; composite_type a = qMin(dst, src2); composite_type b = qMax(src2-Arithmetic::unitValue(), a); return T(b); } template inline T cfArcTangent(T src, T dst) { using namespace Arithmetic; if(dst == zeroValue()) return (src == zeroValue()) ? zeroValue() : unitValue(); return scale(2.0 * atan(scale(src) / scale(dst)) / Arithmetic::pi); } template inline T cfAllanon(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; // (dst + src) / 2 [or (dst + src) * 0.5] return T((composite_type(src) + dst) * halfValue() / unitValue()); } template inline T cfLinearLight(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; // min(1,max(0,(dst + 2*src)-1)) return clamp((composite_type(src) + src + dst) - unitValue()); } template inline T cfParallel(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; // min(max(2 / (1/dst + 1/src), 0), 1) composite_type unit = unitValue(); composite_type s = (src != zeroValue()) ? div(unit, src) : unit; - composite_type d = (dst != zeroValue()) ? div(unit, dst) : unit; + composite_type d = (dst != zeroValue()) ? div(unit, dst) : unit; + if (src == zeroValue()) { + return zeroValue(); + } + + if (dst == zeroValue()) { + return zeroValue(); + } + return clamp((unit+unit) * unit / (d+s)); } template inline T cfEquivalence(T src, T dst) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; // 1 - abs(dst - src) composite_type x = composite_type(dst) - src; return (x < Arithmetic::zeroValue()) ? T(-x) : T(x); } template inline T cfGrainMerge(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; return clamp(composite_type(dst) + src - halfValue()); } template inline T cfGrainExtract(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; return clamp(composite_type(dst) - src + halfValue()); } template inline T cfHardMix(T src, T dst) { return (dst > Arithmetic::halfValue()) ? cfColorDodge(src,dst) : cfColorBurn(src,dst); } template inline T cfHardMixPhotoshop(T src, T dst) { using namespace Arithmetic; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; const composite_type sum = composite_type(src) + dst; return sum > unitValue() ? unitValue() : zeroValue(); } template inline T cfAdditiveSubtractive(T src, T dst) { using namespace Arithmetic; // min(1,max(0,abs(sqr(CB)-sqr(CT)))) qreal x = sqrt(scale(dst)) - sqrt(scale(src)); return scale((x < 0.0) ? -x : x); } template inline T cfGammaDark(T src, T dst) { using namespace Arithmetic; if(src == zeroValue()) return zeroValue(); // power(dst, 1/src) return scale(pow(scale(dst), 1.0/scale(src))); } template inline T cfGammaLight(T src, T dst) { using namespace Arithmetic; return scale(pow(scale(dst), scale(src))); } +template +inline T cfGammaIllumination(T src, T dst) { + using namespace Arithmetic; + return inv(cfGammaDark(inv(src),inv(dst))); +} + template inline T cfGeometricMean(T src, T dst) { using namespace Arithmetic; return scale(sqrt(scale(dst) * scale(src))); } template inline T cfOver(T src, T dst) { Q_UNUSED(dst); return src; } template inline T cfOverlay(T src, T dst) { return cfHardLight(dst, src); } template inline T cfMultiply(T src, T dst) { return Arithmetic::mul(src, dst); } template inline T cfHardOverlay(T src, T dst) { using namespace Arithmetic; qreal fsrc = scale(src); qreal fdst = scale(dst); + + if (fsrc == 1.0) { + return scale(1.0);} if(fsrc > 0.5f) { return scale(cfDivide(inv(2.0 * fsrc - 1.0f), fdst)); } return scale(mul(2.0 * fsrc, fdst)); } template inline T cfDifference(T src, T dst) { return qMax(src,dst) - qMin(src,dst); } template inline T cfScreen(T src, T dst) { return Arithmetic::unionShapeOpacity(src, dst); } template inline T cfDarkenOnly(T src, T dst) { return qMin(src, dst); } template inline T cfLightenOnly(T src, T dst) { return qMax(src, dst); } template inline T cfGlow(T src, T dst) { using namespace Arithmetic; // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat + + if (dst == unitValue()) { + return unitValue(); + } + + return clamp(div(mul(src, src), inv(dst))); +} + +template +inline T cfReflect(T src, T dst) { + using namespace Arithmetic; - if(dst == unitValue()) { + + return clamp(cfGlow(dst,src)); +} + +template +inline T cfHeat(T src, T dst) { + using namespace Arithmetic; + + if(src == unitValue()) { return unitValue(); } - if(src == zeroValue()) { + if(dst == zeroValue()) { return zeroValue(); } + + return inv(clamp(div(mul(inv(src), inv(src)),dst))); +} + +template +inline T cfFreeze(T src, T dst) { + using namespace Arithmetic; - return clamp(div(mul(src, src), inv(dst))); + return (cfHeat(dst,src)); } + +template +inline T cfHelow(T src, T dst) { + using namespace Arithmetic; + // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat + if (cfHardMixPhotoshop(src,dst) == unitValue()) { + return cfHeat(src,dst); + } + + if (src == zeroValue()) { + return zeroValue(); + } + + return (cfGlow(src,dst)); +} + template -inline T cfReflect(T src, T dst) { +inline T cfFrect(T src, T dst) { + using namespace Arithmetic; + + if (cfHardMixPhotoshop(src,dst) == unitValue()) { + return cfFreeze(src,dst); + } + + if (dst == zeroValue()) { + return zeroValue(); + } + + return (cfReflect(src,dst)); +} + +template +inline T cfGleat(T src, T dst) { using namespace Arithmetic; + // see http://www.pegtop.net/delphi/articles/blendmodes/quadratic.htm for formulas of Quadratic Blending Modes like Glow, Reflect, Freeze, and Heat + + if(dst == unitValue()) { + return unitValue(); + } - return (cfGlow(dst,src)); + if(cfHardMixPhotoshop(src,dst) == unitValue()) { + return cfGlow(src,dst); + } + + return (cfHeat(src,dst)); } template -inline T cfHeat(T src, T dst) { +inline T cfReeze(T src, T dst) { using namespace Arithmetic; - // Heat, and Freeze only works properly on 8-bit images. It does not work properly on any other color depth. For now, if Heat and Freeze are proven useful for 8-bit painting, then there should be some way of solving this issue. - if(dst == zeroValue()) { + return (cfGleat(dst,src)); +} +template +inline T cfFhyrd(T src, T dst) { + using namespace Arithmetic; + + return (cfAllanon(cfFrect(src,dst),cfHelow(src,dst))); +} + +template +inline T cfInterpolation(T src, T dst) { + using namespace Arithmetic; + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if(dst == zeroValue() && src == zeroValue()) { return zeroValue(); + } + + return scale(.5f-.25f*cos(pi*(fsrc))-.25f*cos(pi*(fdst))); +} + +template +inline T cfInterpolationB(T src, T dst) { + using namespace Arithmetic; + + return cfInterpolation(cfInterpolation(src,dst),cfInterpolation(src,dst)); +} + + +template +inline T cfPenumbraB(T src, T dst) { + using namespace Arithmetic; + + if (dst == unitValue()) { + return unitValue(); + } + if (dst + src < unitValue()) { + return (cfColorDodge(dst,src)/2); } + if (src == zeroValue()) { + return zeroValue(); + } + + return inv(clamp(div(inv(dst),src)/2)); +} + +template +inline T cfPenumbraD(T src, T dst) { + using namespace Arithmetic; - if(src == unitValue()) { + if (dst == unitValue()) { return unitValue(); } - return inv(clamp(div(mul(inv(src), inv(src)),dst))); + return cfArcTangent(src,inv(dst)); } template -inline T cfFreeze(T src, T dst) { +inline T cfPenumbraC(T src, T dst) { + using namespace Arithmetic; + + return cfPenumbraD(dst,src); +} + +template +inline T cfPenumbraA(T src, T dst) { + using namespace Arithmetic; + + return (cfPenumbraB(dst,src)); +} + +template +inline T cfSoftLightIFSIllusions(T src, T dst) { + using namespace Arithmetic; + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + return scale(pow(fdst,pow(2.0,(mul(2.0,.5f-fsrc))))); +} + +template +inline T cfSoftLightPegtopDelphi(T src, T dst) { + using namespace Arithmetic; + + return clamp(cfAddition(mul(dst,cfScreen(src,dst)),mul(mul(src,dst),inv(dst)))); +} + +template +inline T cfNegation(T src, T dst) { + using namespace Arithmetic; + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + + composite_type unit = unitValue(); + composite_type a = unit - src - dst; + composite_type s = abs(a); + composite_type d = unit - s; + + return T(d); +} + +template +inline T cfNor(T src, T dst) { + using namespace Arithmetic; + + return and(src,dst); +} + +template +inline T cfNand(T src, T dst) { + using namespace Arithmetic; + + return or(src,dst); +} + +template +inline T cfXor(T src, T dst) { + using namespace Arithmetic; + + return xor(src,dst); +} + +template +inline T cfXnor(T src, T dst) { + using namespace Arithmetic; + + return cfXor(src,inv(dst)); +} + +template +inline T cfAnd(T src, T dst) { using namespace Arithmetic; + + return cfNor(inv(src),inv(dst)); +} + +template +inline T cfOr(T src, T dst) { + using namespace Arithmetic; + + return cfNand(inv(src),inv(dst)); +} + +template +inline T cfConverse(T src, T dst) { + using namespace Arithmetic; + + return cfOr(inv(src),dst); +} + +template +inline T cfNotConverse(T src, T dst) { + using namespace Arithmetic; + + return cfAnd(src,inv(dst)); +} + +template +inline T cfImplies(T src, T dst) { + using namespace Arithmetic; + + return cfOr(src,inv(dst)); +} + +template +inline T cfNotImplies(T src, T dst) { + using namespace Arithmetic; + + return cfAnd(inv(src),dst); +} + +template +inline T cfPNormA(T src, T dst) { + using namespace Arithmetic; + //This is also known as P-Norm mode with factor of 2.3333 See IMBLEND image blending mode samples, and please see imblend.m file found on Additional Blending Mode thread at Phabricator. 1/2.3333 is .42875... + + return clamp(pow(pow(dst,2.3333333333333333)+pow(src,2.3333333333333333),0.428571428571434)); +} + +template +inline T cfPNormB(T src, T dst) { + using namespace Arithmetic; + //This is also known as P-Norm mode with factor of 2.3333 See IMBLEND image blending mode samples, and please see imblend.m file found on Additional Blending Mode thread at Phabricator. 1/2.3333 is .42875... + + return clamp(pow(pow(dst,4)+pow(src,4),0.25)); +} + +template +inline T cfSuperLight(T src, T dst) { + using namespace Arithmetic; + //4.0 can be adjusted to taste. 4.0 is picked for being the best in terms of contrast and details. See imblend.m file. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc < .5) { + return scale(inv(pow(pow(inv(fdst),2.875)+pow(inv(2.0*fsrc),2.875),1.0/2.875))); + } + + return scale(pow(pow(fdst,2.875)+pow(2.0*fsrc-1.0,2.875),1.0/2.875)); +} + +template +inline T cfTintIFSIllusions(T src, T dst) { + using namespace Arithmetic; + //Known as Light Blending mode found in IFS Illusions. Picked this name because it results into a very strong tint, and has better naming convention. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + return scale(fsrc*inv(fdst)+sqrt(fdst)); +} + +template +inline T cfShadeIFSIllusions(T src, T dst) { + using namespace Arithmetic; + //Known as Shadow Blending mode found in IFS Illusions. Picked this name because it is the opposite of Tint (IFS Illusion Blending mode). + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + return scale(inv((inv(fdst)*fsrc)+sqrt(inv(fsrc)))); +} + +template +inline T cfFogLightenIFSIllusions(T src, T dst) { + using namespace Arithmetic; + //Known as Bright Blending mode found in IFS Illusions. Picked this name because the shading reminds me of fog when overlaying with a gradientt. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc < .5) { + return scale(inv(inv(fsrc)*fsrc)-inv(fdst)*inv(fsrc)); + } + + return scale(fsrc-inv(fdst)*inv(fsrc)+pow(inv(fsrc),2)); +} + +template +inline T cfFogDarkenIFSIllusions(T src, T dst) { + using namespace Arithmetic; + //Known as Dark Blending mode found in IFS Illusions. Picked this name because the shading reminds me of fog when overlaying with a gradient. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc < .5) { + return scale(inv(fsrc)*fsrc+fsrc*fdst); + } + + return scale(fsrc*fdst+fsrc-pow(fsrc,2)); +} + +template +inline T cfModulo(T src, T dst) { + using namespace Arithmetic; + + return mod(dst,src); +} + +template +inline T cfModuloShift(T src, T dst) { + using namespace Arithmetic; + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc == 1.0 && fdst == 0.0) { + return scale(0.0); + } + - return clamp(cfHeat(dst,src)); + return scale(mod((fdst+fsrc),1.0000000000)); } +template +inline T cfModuloShiftContinuous(T src, T dst) { + using namespace Arithmetic; + //This blending mode do not behave like difference/equilavent with destination layer inverted if you use group layer on addition while the content of group layer contains several addition-mode layers, it works as expected on float images. So, no need to change this. + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc == 1.0 && fdst == 0.0) { + return scale(0.0); + } + + return scale((int(ceil(fdst+fsrc)) % 2 != 0) || (fdst == zeroValue()) ? inv(cfModuloShift(fsrc,fdst)) : cfModuloShift(fsrc,fdst)); +} +template +inline T cfDivisiveModulo(T src, T dst) { + using namespace Arithmetic; + //I have to use 1.00000 as unitValue failed to work for those area. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc == zeroValue()) { + return scale(mod(((1.0000000000/epsilon()) * fdst),1.0000000000)); + } + + return scale(mod(((1.0000000000/fsrc) * fdst),1.0000000000)); +} + +template +inline T cfDivisiveModuloContinuous(T src, T dst) { + using namespace Arithmetic; + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fdst == zeroValue()) { + return zeroValue(); + } + + if (fsrc == zeroValue()) { + return cfDivisiveModulo(fsrc,fdst); + } + + + return scale( int(ceil(fdst/fsrc)) % 2 != 0 ? cfDivisiveModulo(fsrc,fdst) : inv(cfDivisiveModulo(fsrc,fdst))); +} + +template +inline T cfModuloContinuous(T src, T dst) { + using namespace Arithmetic; + + return cfMultiply(cfDivisiveModuloContinuous(src,dst),src); +} + +template +inline T cfColorBurnLogarithmic(T src, T dst) { + using namespace Arithmetic; + //Also known as Darken from EffectBank/Illusions.hu. IFS Illusions had used this blending mode. + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (inv(fdst) == zeroValue()) { + return scale(log2(1.0 + abs(fsrc)/abs(inv(.999999))/8)); + } + + return scale(log2(1.0 + abs(fsrc)/abs(inv(fdst))/8)); +} + +template +inline T cfColorDodgeLogarithmic(T src, T dst) { + using namespace Arithmetic; + //Also known as Lighten from EffectBank/Illusions.hu. IFS Illusions had used this blending mode. + + return inv(cfColorBurnLogarithmic(inv(src),inv(dst))); +} + +template +inline T cfEasyDodge(T src, T dst) { + using namespace Arithmetic; + // The 13 divided by 15 can be adjusted to taste. See imgblend.m + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + if (fsrc == 1.0) { + return scale(1.0);} + + + return scale(pow(fdst,mul(inv(fsrc != 1.0 ? fsrc : .999999999999),1.039999999))); +} + +template +inline T cfEasyBurn(T src, T dst) { + using namespace Arithmetic; + // The 13 divided by 15 can be adjusted to taste. See imgblend.m + + qreal fsrc = scale(src); + qreal fdst = scale(dst); + + + return scale(inv(pow(inv(fsrc != 1.0 ? fsrc : .999999999999),mul(fdst,1.039999999)))); +} + +template +inline T cfFlatLight(T src, T dst) { + using namespace Arithmetic; + + if (src == zeroValue()) { + return zeroValue(); + } + + return clamp(cfHardMixPhotoshop(inv(src),dst)==unitValue() ? cfPenumbraB(src,dst) : cfPenumbraA(src,dst)); +} #endif // KOCOMPOSITEOP_FUNCTIONS_H_ diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h index 4a8bd72073..7dff0ebeb7 100644 --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -1,270 +1,315 @@ /* * Copyright (c) 2007 Cyrille Berger * Copyright (c) 2011 Silvio Heinrich * * 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 _KOCOMPOSITEOPS_H_ #define _KOCOMPOSITEOPS_H_ #include #include #include #include #include "compositeops/KoCompositeOpGeneric.h" #include "compositeops/KoCompositeOpOver.h" #include "compositeops/KoCompositeOpCopyChannel.h" #include "compositeops/KoCompositeOpAlphaDarken.h" #include "compositeops/KoCompositeOpErase.h" #include "compositeops/KoCompositeOpCopy2.h" #include "compositeops/KoCompositeOpDissolve.h" #include "compositeops/KoCompositeOpBehind.h" #include "compositeops/KoCompositeOpDestinationIn.h" #include "compositeops/KoCompositeOpDestinationAtop.h" #include "compositeops/KoCompositeOpGreater.h" #include "compositeops/KoAlphaDarkenParamsWrapper.h" #include "KoOptimizedCompositeOpFactory.h" namespace _Private { template struct AddGeneralOps { static void add(KoColorSpace* cs) { Q_UNUSED(cs); } }; template struct OptimizedOpsSelector { static KoCompositeOp* createAlphaDarkenOp(const KoColorSpace *cs) { if (useCreamyAlphaDarken()) { return new KoCompositeOpAlphaDarken(cs); } else { return new KoCompositeOpAlphaDarken(cs); } } static KoCompositeOp* createOverOp(const KoColorSpace *cs) { return new KoCompositeOpOver(cs); } }; template<> struct OptimizedOpsSelector { static KoCompositeOp* createAlphaDarkenOp(const KoColorSpace *cs) { return useCreamyAlphaDarken() ? KoOptimizedCompositeOpFactory::createAlphaDarkenOpCreamy32(cs) : KoOptimizedCompositeOpFactory::createAlphaDarkenOpHard32(cs); } static KoCompositeOp* createOverOp(const KoColorSpace *cs) { return KoOptimizedCompositeOpFactory::createOverOp32(cs); } }; template<> struct OptimizedOpsSelector { static KoCompositeOp* createAlphaDarkenOp(const KoColorSpace *cs) { return useCreamyAlphaDarken() ? KoOptimizedCompositeOpFactory::createAlphaDarkenOpCreamy32(cs) : KoOptimizedCompositeOpFactory::createAlphaDarkenOpHard32(cs); } static KoCompositeOp* createOverOp(const KoColorSpace *cs) { return KoOptimizedCompositeOpFactory::createOverOp32(cs); } }; template<> struct OptimizedOpsSelector { static KoCompositeOp* createAlphaDarkenOp(const KoColorSpace *cs) { return useCreamyAlphaDarken() ? KoOptimizedCompositeOpFactory::createAlphaDarkenOpCreamy128(cs) : KoOptimizedCompositeOpFactory::createAlphaDarkenOpHard128(cs); } static KoCompositeOp* createOverOp(const KoColorSpace *cs) { return KoOptimizedCompositeOpFactory::createOverOp128(cs); } }; template struct AddGeneralOps { typedef typename Traits::channels_type Arg; typedef Arg (*CompositeFunc)(Arg, Arg); static const qint32 alpha_pos = Traits::alpha_pos; template static void add(KoColorSpace* cs, const QString& id, const QString& description, const QString& category) { cs->addCompositeOp(new KoCompositeOpGenericSC(cs, id, description, category)); } static void add(KoColorSpace* cs) { cs->addCompositeOp(OptimizedOpsSelector::createOverOp(cs)); cs->addCompositeOp(OptimizedOpsSelector::createAlphaDarkenOp(cs)); cs->addCompositeOp(new KoCompositeOpCopy2(cs)); cs->addCompositeOp(new KoCompositeOpErase(cs)); cs->addCompositeOp(new KoCompositeOpBehind(cs)); cs->addCompositeOp(new KoCompositeOpDestinationIn(cs)); cs->addCompositeOp(new KoCompositeOpDestinationAtop(cs)); cs->addCompositeOp(new KoCompositeOpGreater(cs)); add<&cfOverlay >(cs, COMPOSITE_OVERLAY , i18n("Overlay") , KoCompositeOp::categoryMix()); add<&cfGrainMerge >(cs, COMPOSITE_GRAIN_MERGE , i18n("Grain Merge") , KoCompositeOp::categoryMix()); add<&cfGrainExtract >(cs, COMPOSITE_GRAIN_EXTRACT , i18n("Grain Extract") , KoCompositeOp::categoryMix()); add<&cfHardMix >(cs, COMPOSITE_HARD_MIX , i18n("Hard Mix") , KoCompositeOp::categoryMix()); add<&cfHardMixPhotoshop>(cs, COMPOSITE_HARD_MIX_PHOTOSHOP, i18n("Hard Mix (Photoshop)") , KoCompositeOp::categoryMix()); add<&cfGeometricMean >(cs, COMPOSITE_GEOMETRIC_MEAN, i18n("Geometric Mean"), KoCompositeOp::categoryMix()); add<&cfParallel >(cs, COMPOSITE_PARALLEL , i18n("Parallel") , KoCompositeOp::categoryMix()); add<&cfAllanon >(cs, COMPOSITE_ALLANON , i18n("Allanon") , KoCompositeOp::categoryMix()); add<&cfHardOverlay >(cs, COMPOSITE_HARD_OVERLAY , i18n("Hard Overlay") , KoCompositeOp::categoryMix()); + add<&cfInterpolation >(cs, COMPOSITE_INTERPOLATION , i18n("Interpolation") , KoCompositeOp::categoryMix()); + add<&cfInterpolationB >(cs, COMPOSITE_INTERPOLATIONB , i18n("Interpolation - 2X") , KoCompositeOp::categoryMix()); + add<&cfPenumbraA >(cs, COMPOSITE_PENUMBRAA , i18n("Penumbra A") , KoCompositeOp::categoryMix()); + add<&cfPenumbraB >(cs, COMPOSITE_PENUMBRAB , i18n("Penumbra B") , KoCompositeOp::categoryMix()); + add<&cfPenumbraC >(cs, COMPOSITE_PENUMBRAC , i18n("Penumbra C") , KoCompositeOp::categoryMix()); + add<&cfPenumbraD >(cs, COMPOSITE_PENUMBRAD , i18n("Penumbra D") , KoCompositeOp::categoryMix()); add<&cfScreen >(cs, COMPOSITE_SCREEN , i18n("Screen") , KoCompositeOp::categoryLight()); add<&cfColorDodge >(cs, COMPOSITE_DODGE , i18n("Color Dodge") , KoCompositeOp::categoryLight()); add<&cfAddition >(cs, COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), KoCompositeOp::categoryLight()); add<&cfLightenOnly >(cs, COMPOSITE_LIGHTEN , i18n("Lighten") , KoCompositeOp::categoryLight()); add<&cfHardLight >(cs, COMPOSITE_HARD_LIGHT , i18n("Hard Light") , KoCompositeOp::categoryLight()); + add<&cfSoftLightIFSIllusions>(cs, COMPOSITE_SOFT_LIGHT_IFS_ILLUSIONS, i18n("Soft Light (IFS Illusions)") , KoCompositeOp::categoryLight()); + add<&cfSoftLightPegtopDelphi>(cs, COMPOSITE_SOFT_LIGHT_PEGTOP_DELPHI, i18n("Soft Light (Pegtop-Delphi)") , KoCompositeOp::categoryLight()); add<&cfSoftLightSvg >(cs, COMPOSITE_SOFT_LIGHT_SVG, i18n("Soft Light (SVG)") , KoCompositeOp::categoryLight()); add<&cfSoftLight >(cs, COMPOSITE_SOFT_LIGHT_PHOTOSHOP, i18n("Soft Light (Photoshop)") , KoCompositeOp::categoryLight()); add<&cfGammaLight >(cs, COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light") , KoCompositeOp::categoryLight()); + add<&cfGammaIllumination >(cs, COMPOSITE_GAMMA_ILLUMINATION , i18n("Gamma Illumination") , KoCompositeOp::categoryLight()); add<&cfVividLight >(cs, COMPOSITE_VIVID_LIGHT , i18n("Vivid Light") , KoCompositeOp::categoryLight()); + add<&cfFlatLight >(cs, COMPOSITE_FLAT_LIGHT , i18n("Flat Light") , KoCompositeOp::categoryLight()); add<&cfPinLight >(cs, COMPOSITE_PIN_LIGHT , i18n("Pin Light") , KoCompositeOp::categoryLight()); add<&cfLinearLight >(cs, COMPOSITE_LINEAR_LIGHT, i18n("Linear Light"), KoCompositeOp::categoryLight()); + add<&cfPNormA >(cs, COMPOSITE_PNORM_A , i18n("P-Norm A") , KoCompositeOp::categoryLight()); + add<&cfPNormB >(cs, COMPOSITE_PNORM_B , i18n("P-Norm B") , KoCompositeOp::categoryLight()); + add<&cfSuperLight >(cs, COMPOSITE_SUPER_LIGHT , i18n("Super Light") , KoCompositeOp::categoryLight()); + add<&cfTintIFSIllusions >(cs, COMPOSITE_TINT_IFS_ILLUSIONS , i18n("Tint (IFS Illusions)") , KoCompositeOp::categoryLight()); + add<&cfFogLightenIFSIllusions >(cs, COMPOSITE_FOG_LIGHTEN_IFS_ILLUSIONS , i18n("Fog Lighten (IFS Illusions)") , KoCompositeOp::categoryLight()); + add<&cfColorDodgeLogarithmic >(cs, COMPOSITE_DODGE_LOGARITHMIC , i18n("Color Dodge - Logarithmic") , KoCompositeOp::categoryLight()); + add<&cfEasyDodge >(cs, COMPOSITE_EASY_DODGE , i18n("Easy Dodge") , KoCompositeOp::categoryLight()); add<&cfColorBurn >(cs, COMPOSITE_BURN , i18n("Color Burn") , KoCompositeOp::categoryDark()); add<&cfLinearBurn >(cs, COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), KoCompositeOp::categoryDark()); add<&cfDarkenOnly >(cs, COMPOSITE_DARKEN , i18n("Darken") , KoCompositeOp::categoryDark()); add<&cfGammaDark >(cs, COMPOSITE_GAMMA_DARK , i18n("Gamma Dark") , KoCompositeOp::categoryDark()); + add<&cfShadeIFSIllusions >(cs, COMPOSITE_SHADE_IFS_ILLUSIONS , i18n("Shade (IFS_Illusions)") , KoCompositeOp::categoryDark()); + add<&cfFogDarkenIFSIllusions >(cs, COMPOSITE_FOG_DARKEN_IFS_ILLUSIONS , i18n("Fog Darken (IFS Illusions)") , KoCompositeOp::categoryDark()); + add<&cfColorBurnLogarithmic >(cs, COMPOSITE_BURN_LOGARITHMIC , i18n("Color Burn - Logarithmic") , KoCompositeOp::categoryDark()); + add<&cfEasyBurn >(cs, COMPOSITE_EASY_BURN , i18n("Easy Burn") , KoCompositeOp::categoryDark()); add<&cfAddition >(cs, COMPOSITE_ADD , i18n("Addition") , KoCompositeOp::categoryArithmetic()); add<&cfSubtract >(cs, COMPOSITE_SUBTRACT , i18n("Subtract") , KoCompositeOp::categoryArithmetic()); add<&cfInverseSubtract >(cs, COMPOSITE_INVERSE_SUBTRACT, i18n("Inversed-Subtract"), KoCompositeOp::categoryArithmetic()); add<&cfMultiply >(cs, COMPOSITE_MULT , i18n("Multiply") , KoCompositeOp::categoryArithmetic()); add<&cfDivide >(cs, COMPOSITE_DIVIDE , i18n("Divide") , KoCompositeOp::categoryArithmetic()); + add<&cfModulo >(cs, COMPOSITE_MOD , i18n("Modulo") , KoCompositeOp::categoryModulo()); + add<&cfModuloContinuous >(cs, COMPOSITE_MOD_CON , i18n("Modulo - Continuous") , KoCompositeOp::categoryModulo()); + add<&cfDivisiveModulo >(cs, COMPOSITE_DIVISIVE_MOD , i18n("Divisive Modulo") , KoCompositeOp::categoryModulo()); + add<&cfDivisiveModuloContinuous >(cs, COMPOSITE_DIVISIVE_MOD_CON , i18n("Divisive Modulo - Continuous") , KoCompositeOp::categoryModulo()); + add<&cfModuloShift >(cs, COMPOSITE_MODULO_SHIFT , i18n("Modulo Shift") , KoCompositeOp::categoryModulo()); + add<&cfModuloShiftContinuous >(cs, COMPOSITE_MODULO_SHIFT_CON , i18n("Modulo Shift - Continuous") , KoCompositeOp::categoryModulo()); + add<&cfArcTangent >(cs, COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent") , KoCompositeOp::categoryNegative()); add<&cfDifference >(cs, COMPOSITE_DIFF , i18n("Difference") , KoCompositeOp::categoryNegative()); add<&cfExclusion >(cs, COMPOSITE_EXCLUSION , i18n("Exclusion") , KoCompositeOp::categoryNegative()); add<&cfEquivalence >(cs, COMPOSITE_EQUIVALENCE , i18n("Equivalence") , KoCompositeOp::categoryNegative()); add<&cfAdditiveSubtractive >(cs, COMPOSITE_ADDITIVE_SUBTRACTIVE , i18n("Additive-Subtractive") , KoCompositeOp::categoryNegative()); + add<&cfNegation >(cs, COMPOSITE_NEGATION , i18n("Negation") , KoCompositeOp::categoryNegative()); - add<&cfReflect >(cs, COMPOSITE_REFLECT , i18n("Reflect") , KoCompositeOp::categoryQuadratic()); - add<&cfGlow >(cs, COMPOSITE_GLOW , i18n("Glow") , KoCompositeOp::categoryQuadratic()); - add<&cfFreeze >(cs, COMPOSITE_FREEZE , i18n("Freeze") , KoCompositeOp::categoryQuadratic()); - add<&cfHeat >(cs, COMPOSITE_HEAT , i18n("Heat") , KoCompositeOp::categoryQuadratic()); + add<&cfXor >(cs, COMPOSITE_XOR , i18n("XOR") , KoCompositeOp::categoryBinary()); + add<&cfOr >(cs, COMPOSITE_OR , i18n("OR") , KoCompositeOp::categoryBinary()); + add<&cfAnd >(cs, COMPOSITE_AND , i18n("AND") , KoCompositeOp::categoryBinary()); + add<&cfNand >(cs, COMPOSITE_NAND , i18n("NAND") , KoCompositeOp::categoryBinary()); + add<&cfNor >(cs, COMPOSITE_NOR , i18n("NOR") , KoCompositeOp::categoryBinary()); + add<&cfXnor >(cs, COMPOSITE_XNOR , i18n("XNOR") , KoCompositeOp::categoryBinary()); + add<&cfImplies >(cs, COMPOSITE_IMPLICATION , i18n("IMPLICATION") , KoCompositeOp::categoryBinary()); + add<&cfNotImplies >(cs, COMPOSITE_NOT_IMPLICATION , i18n("NOT IMPLICATION") , KoCompositeOp::categoryBinary()); + add<&cfConverse >(cs, COMPOSITE_CONVERSE , i18n("CONVERSE") , KoCompositeOp::categoryBinary()); + add<&cfNotConverse >(cs, COMPOSITE_NOT_CONVERSE , i18n("NOT CONVERSE") , KoCompositeOp::categoryBinary()); + + add<&cfReflect >(cs, COMPOSITE_REFLECT , i18n("Reflect") , KoCompositeOp::categoryQuadratic()); + add<&cfGlow >(cs, COMPOSITE_GLOW , i18n("Glow") , KoCompositeOp::categoryQuadratic()); + add<&cfFreeze >(cs, COMPOSITE_FREEZE , i18n("Freeze") , KoCompositeOp::categoryQuadratic()); + add<&cfHeat >(cs, COMPOSITE_HEAT , i18n("Heat") , KoCompositeOp::categoryQuadratic()); + add<&cfGleat >(cs, COMPOSITE_GLEAT , i18n("Glow-Heat") , KoCompositeOp::categoryQuadratic()); + add<&cfHelow >(cs, COMPOSITE_HELOW , i18n("Heat-Glow") , KoCompositeOp::categoryQuadratic()); + add<&cfReeze >(cs, COMPOSITE_REEZE , i18n("Reflect-Freeze") , KoCompositeOp::categoryQuadratic()); + add<&cfFrect >(cs, COMPOSITE_FRECT , i18n("Freeze-Reflect") , KoCompositeOp::categoryQuadratic()); + add<&cfFhyrd >(cs, COMPOSITE_FHYRD , i18n("Heat-Glow & Freeze-Reflect Hybrid") , KoCompositeOp::categoryQuadratic()); cs->addCompositeOp(new KoCompositeOpDissolve(cs, KoCompositeOp::categoryMisc())); } }; template struct AddRGBOps { static void add(KoColorSpace* cs) { Q_UNUSED(cs); } }; template struct AddRGBOps { typedef float Arg; static const qint32 red_pos = Traits::red_pos; static const qint32 green_pos = Traits::green_pos; static const qint32 blue_pos = Traits::blue_pos; template static void add(KoColorSpace* cs, const QString& id, const QString& description, const QString& category) { cs->addCompositeOp(new KoCompositeOpGenericHSL(cs, id, description, category)); } static void add(KoColorSpace* cs) { cs->addCompositeOp(new KoCompositeOpCopyChannel(cs, COMPOSITE_COPY_RED , i18n("Copy Red") , KoCompositeOp::categoryMisc())); cs->addCompositeOp(new KoCompositeOpCopyChannel(cs, COMPOSITE_COPY_GREEN, i18n("Copy Green"), KoCompositeOp::categoryMisc())); cs->addCompositeOp(new KoCompositeOpCopyChannel(cs, COMPOSITE_COPY_BLUE , i18n("Copy Blue") , KoCompositeOp::categoryMisc())); add<&cfTangentNormalmap >(cs, COMPOSITE_TANGENT_NORMALMAP , i18n("Tangent Normalmap") , KoCompositeOp::categoryMisc()); add<&cfReorientedNormalMapCombine >(cs, COMPOSITE_COMBINE_NORMAL, i18n("Combine Normal Maps"), KoCompositeOp::categoryMisc()); add<&cfColor >(cs, COMPOSITE_COLOR , i18n("Color") , KoCompositeOp::categoryHSY()); add<&cfHue >(cs, COMPOSITE_HUE , i18n("Hue") , KoCompositeOp::categoryHSY()); add<&cfSaturation >(cs, COMPOSITE_SATURATION , i18n("Saturation") , KoCompositeOp::categoryHSY()); add<&cfIncreaseSaturation >(cs, COMPOSITE_INC_SATURATION, i18n("Increase Saturation"), KoCompositeOp::categoryHSY()); add<&cfDecreaseSaturation >(cs, COMPOSITE_DEC_SATURATION, i18n("Decrease Saturation"), KoCompositeOp::categoryHSY()); add<&cfLightness >(cs, COMPOSITE_LUMINIZE , i18n("Luminosity") , KoCompositeOp::categoryHSY()); add<&cfIncreaseLightness >(cs, COMPOSITE_INC_LUMINOSITY, i18n("Increase Luminosity"), KoCompositeOp::categoryHSY()); add<&cfDecreaseLightness >(cs, COMPOSITE_DEC_LUMINOSITY, i18n("Decrease Luminosity"), KoCompositeOp::categoryHSY()); add<&cfDarkerColor >(cs, COMPOSITE_DARKER_COLOR, i18n("Darker Color"), KoCompositeOp::categoryDark());//darker color as PSD does it// add<&cfLighterColor >(cs, COMPOSITE_LIGHTER_COLOR, i18n("Lighter Color"), KoCompositeOp::categoryLight());//lighter color as PSD does it// add<&cfColor >(cs, COMPOSITE_COLOR_HSI , i18n("Color HSI") , KoCompositeOp::categoryHSI()); add<&cfHue >(cs, COMPOSITE_HUE_HSI , i18n("Hue HSI") , KoCompositeOp::categoryHSI()); add<&cfSaturation >(cs, COMPOSITE_SATURATION_HSI , i18n("Saturation HSI") , KoCompositeOp::categoryHSI()); add<&cfIncreaseSaturation >(cs, COMPOSITE_INC_SATURATION_HSI, i18n("Increase Saturation HSI"), KoCompositeOp::categoryHSI()); add<&cfDecreaseSaturation >(cs, COMPOSITE_DEC_SATURATION_HSI, i18n("Decrease Saturation HSI"), KoCompositeOp::categoryHSI()); add<&cfLightness >(cs, COMPOSITE_INTENSITY , i18n("Intensity") , KoCompositeOp::categoryHSI()); add<&cfIncreaseLightness >(cs, COMPOSITE_INC_INTENSITY , i18n("Increase Intensity") , KoCompositeOp::categoryHSI()); add<&cfDecreaseLightness >(cs, COMPOSITE_DEC_INTENSITY , i18n("Decrease Intensity") , KoCompositeOp::categoryHSI()); add<&cfColor >(cs, COMPOSITE_COLOR_HSL , i18n("Color HSL") , KoCompositeOp::categoryHSL()); add<&cfHue >(cs, COMPOSITE_HUE_HSL , i18n("Hue HSL") , KoCompositeOp::categoryHSL()); add<&cfSaturation >(cs, COMPOSITE_SATURATION_HSL , i18n("Saturation HSL") , KoCompositeOp::categoryHSL()); add<&cfIncreaseSaturation >(cs, COMPOSITE_INC_SATURATION_HSL, i18n("Increase Saturation HSL"), KoCompositeOp::categoryHSL()); add<&cfDecreaseSaturation >(cs, COMPOSITE_DEC_SATURATION_HSL, i18n("Decrease Saturation HSL"), KoCompositeOp::categoryHSL()); add<&cfLightness >(cs, COMPOSITE_LIGHTNESS , i18n("Lightness") , KoCompositeOp::categoryHSL()); add<&cfIncreaseLightness >(cs, COMPOSITE_INC_LIGHTNESS , i18n("Increase Lightness") , KoCompositeOp::categoryHSL()); add<&cfDecreaseLightness >(cs, COMPOSITE_DEC_LIGHTNESS , i18n("Decrease Lightness") , KoCompositeOp::categoryHSL()); add<&cfColor >(cs, COMPOSITE_COLOR_HSV , i18n("Color HSV") , KoCompositeOp::categoryHSV()); add<&cfHue >(cs, COMPOSITE_HUE_HSV , i18n("Hue HSV") , KoCompositeOp::categoryHSV()); add<&cfSaturation >(cs, COMPOSITE_SATURATION_HSV , i18n("Saturation HSV") , KoCompositeOp::categoryHSV()); add<&cfIncreaseSaturation >(cs, COMPOSITE_INC_SATURATION_HSV, i18n("Increase Saturation HSV"), KoCompositeOp::categoryHSV()); add<&cfDecreaseSaturation >(cs, COMPOSITE_DEC_SATURATION_HSV, i18n("Decrease Saturation HSV"), KoCompositeOp::categoryHSV()); add<&cfLightness >(cs, COMPOSITE_VALUE , i18nc("HSV Value","Value") , KoCompositeOp::categoryHSV()); add<&cfIncreaseLightness >(cs, COMPOSITE_INC_VALUE , i18n("Increase Value") , KoCompositeOp::categoryHSV()); add<&cfDecreaseLightness >(cs, COMPOSITE_DEC_VALUE , i18n("Decrease Value") , KoCompositeOp::categoryHSV()); } }; } /** * This function add to the colorspace all the composite ops defined by * the pigment library. */ template void addStandardCompositeOps(KoColorSpace* cs) { typedef typename _Traits_::channels_type channels_type; static const bool useGeneralOps = true; static const bool useRGBOps = (boost::is_base_of, _Traits_>::value || boost::is_base_of, _Traits_>::value); _Private::AddGeneralOps<_Traits_, useGeneralOps>::add(cs); _Private::AddRGBOps <_Traits_, useRGBOps >::add(cs); } template KoCompositeOp* createAlphaDarkenCompositeOp(const KoColorSpace *cs) { return _Private::OptimizedOpsSelector<_Traits_>::createAlphaDarkenOp(cs); } #endif