From kde-kimageshop Wed Jan 12 22:17:04 2011 From: Silvio Heinrich Date: Wed, 12 Jan 2011 22:17:04 +0000 To: kde-kimageshop Subject: Patch: Many composite/blend modes mostly compatible to Adobe Photoshop Message-Id: <4D2E2860.9060107 () web ! de> X-MARC-Message: https://marc.info/?l=kde-kimageshop&m=129487165329588 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--------------080501060900080908060607" This is a multi-part message in MIME format. --------------080501060900080908060607 Content-Type: multipart/alternative; boundary="------------050209040906090300030902" --------------050209040906090300030902 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Phew... I think I've gone a bit mad with the blending modes :D. I added a few. When counting everything together there should be nearly 40 compositing modes now. All modes should trait partly transparent layers as Photoshop is doing it and all modes should respect the channel flags. But there are two problems with this patch: 1. I used a pretty generic approach. So it relies on the compiler to do proper inlining. And i didn't use the optimized multiply functions. I had a few problems with those functions, because it seems the give no correct results but approximations. So I still need to check out which composite modes will work with the optimized functions. I just want to say that it could be that this is a bit/much slower then the current implementation (i don't know how much time you spend in optimizing this). I personally haven't noticed any speed impact but I've got a 3GHz quad core, so i think i will be the last who will notice this. 2. The "Hue" and "Saturation" modes are not working correctly but the "Luminosity" and "Color" modes work exactly as in Photoshop. I coded the algorithms after the ISO 3200-1 spec. Adobe released the texts they gave to the ISO committee for specification. You can find them here: http://www.adobe.com/devnet/pdf.html http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf (direct link) go to the category "Transparency" -> "Basic Composition Computations". This spec is of course for PDFs but it seems that Photoshop uses the same formulas. Since "Luminosity" and "Color" modes are working i think i made some mistake in implementing the "setSat" function (on page 327). Maybe someone else has an enlightenment, because I'm working in the dark right now :D. But apart from this two problems everything else should work fine (hopefully). --------------050209040906090300030902 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Phew... I think I've gone a bit mad with the blending modes :D.
I added a few. When counting everything together there should be nearly 40 compositing modes now.
All modes should trait partly transparent layers as Photoshop is doing it and all modes should
respect the channel flags.
But there are two problems with this patch:

1. I used a pretty generic approach. So it relies on the compiler to do proper inlining. And i didn't use the optimized multiply functions. I had a few problems with those functions, because it seems the give no correct results but approximations. So I still need to check out which composite modes will work with the optimized functions. I just want to say that it could be that this is a bit/much slower then the current implementation (i don't know how much time you spend in optimizing this).
I personally haven't noticed any speed impact but I've got a 3GHz quad core, so i think i will be the last
who will notice this.

2. The "Hue" and "Saturation" modes are not working correctly but the "Luminosity" and "Color" modes work exactly as in Photoshop. I coded the algorithms after the ISO 3200-1 spec. Adobe released the texts they gave to the ISO committee for specification. You can find them here:
http://www.adobe.com/devnet/pdf.html
http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf  (direct link)

go to the category "Transparency" -> "Basic Composition Computations". This spec is of course for PDFs but it seems that Photoshop uses the same formulas.
Since "Luminosity" and "Color" modes are working i think i made some mistake in implementing the
"setSat" function (on page 327). Maybe someone else has an enlightenment, because I'm working in the dark right now :D.

 But apart from this two problems everything else should work fine (hopefully). --------------050209040906090300030902-- --------------080501060900080908060607 Content-Type: text/x-diff; name="BlendModes.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="BlendModes.patch" From a2f91b86e96919ca5ff5a506933d9d798218f93f Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Wed, 5 Jan 2011 00:43:52 +0100 Subject: [PATCH 01/15] Fixed the Burn composite option. Should now work exactly like the Color burn mode in Photoshop but only for fully opaque colors. Transparency is not considered jet. --- libs/pigment/compositeops/KoCompositeOpBurn.h | 25 ++++++++++++++----------- 1 files changed, 14 insertions(+), 11 deletions(-) diff --git a/libs/pigment/compositeops/KoCompositeOpBurn.h b/libs/pigment/compositeops/KoCompositeOpBurn.h index 97feaa4..2a56e2f 100644 --- a/libs/pigment/compositeops/KoCompositeOpBurn.h +++ b/libs/pigment/compositeops/KoCompositeOpBurn.h @@ -29,7 +29,8 @@ template class KoCompositeOpBurn : public KoCompositeOpAlphaBase<_CSTraits, KoCompositeOpBurn<_CSTraits>, true > { typedef typename _CSTraits::channels_type channels_type; - typedef typename KoColorSpaceMathsTraits::compositetype compositetype; + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + public: KoCompositeOpBurn(const KoColorSpace * cs) @@ -48,20 +49,22 @@ public: const QBitArray & channelFlags) { for (uint i = 0; i < _CSTraits::channels_nb; i++) { if ((int)i != _CSTraits::alpha_pos && (allChannelFlags || channelFlags.testBit(i))) { - compositetype srcColor = src[i]; - compositetype dstColor = dst[i]; - - srcColor = qMin(((NATIVE_MAX_VALUE - dstColor) * (NATIVE_MAX_VALUE + 1)) / (srcColor + 1), (compositetype)NATIVE_MAX_VALUE); - if (NATIVE_MAX_VALUE - srcColor > NATIVE_MAX_VALUE) srcColor = NATIVE_MAX_VALUE; - - channels_type newColor = NATIVE_MAX_VALUE - KoColorSpaceMaths::blend(srcColor, dstColor, srcBlend); - - dst[i] = newColor; + composite_type unitValue = KoColorSpaceMathsTraits::unitValue; + composite_type invDst = unitValue - dst[i]; + + if(src[i] != KoColorSpaceMathsTraits::zeroValue) { + composite_type result = unitValue - qMin(invDst * unitValue / src[i], unitValue); + dst[i] = KoColorSpaceMaths::blend(result, dst[i], srcBlend); + } + else { + //composite_type result = KoColorSpaceMathsTraits::zeroValue; + composite_type result = unitValue - qMin(invDst * unitValue, unitValue); + dst[i] = KoColorSpaceMaths::blend(result, dst[i], srcBlend); + } } } } - }; #endif -- 1.7.1 From dd43f07e61d643153e260875276f38f33ae1af03 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Fri, 7 Jan 2011 19:14:15 +0100 Subject: [PATCH 02/15] Made burn and dodge CompositeOs compatible with Adobe Photoshop (c) Added a new generic base class for CompositeOps, currently only used by KoCompositeOpBurn and KoCompositeOpDodge. --- libs/pigment/compositeops/KoCompositeOpBurn.h | 49 ++--- libs/pigment/compositeops/KoCompositeOpDodge.h | 49 +++--- libs/pigment/compositeops/KoCompositeOpFunctions.h | 193 ++++++++++++++++++++ 3 files changed, 236 insertions(+), 55 deletions(-) create mode 100644 libs/pigment/compositeops/KoCompositeOpFunctions.h diff --git a/libs/pigment/compositeops/KoCompositeOpBurn.h b/libs/pigment/compositeops/KoCompositeOpBurn.h index 2a56e2f..3315373 100644 --- a/libs/pigment/compositeops/KoCompositeOpBurn.h +++ b/libs/pigment/compositeops/KoCompositeOpBurn.h @@ -20,51 +20,42 @@ #ifndef KOCOMPOSITEOPBURN_H_ #define KOCOMPOSITEOPBURN_H_ -#include "KoCompositeOpAlphaBase.h" +#include "KoCompositeOpFunctions.h" /** * A template version of the burn composite operation to use in colorspaces. */ template -class KoCompositeOpBurn : public KoCompositeOpAlphaBase<_CSTraits, KoCompositeOpBurn<_CSTraits>, true > +class KoCompositeOpBurn : public KoCompositeOpBase< _CSTraits, KoCompositeOpBurn<_CSTraits> > { typedef typename _CSTraits::channels_type channels_type; typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + static const qint32 channels_nb = _CSTraits::channels_nb; + static const qint32 alpha_pos = _CSTraits::alpha_pos; public: - - KoCompositeOpBurn(const KoColorSpace * cs) - : KoCompositeOpAlphaBase<_CSTraits, KoCompositeOpBurn<_CSTraits>, true >(cs, COMPOSITE_BURN, i18n("Burn"), KoCompositeOp::categoryLight()) { - } + KoCompositeOpBurn(const KoColorSpace* cs) + : KoCompositeOpBase< _CSTraits, KoCompositeOpBurn<_CSTraits> >(cs, COMPOSITE_BURN, i18n("Burn"), KoCompositeOp::categoryLight()) { } public: - inline static channels_type selectAlpha(channels_type srcAlpha, channels_type dstAlpha) { - return qMin(srcAlpha, dstAlpha); - } - - inline static void composeColorChannels(channels_type srcBlend, - const channels_type* src, - channels_type* dst, - bool allChannelFlags, - const QBitArray & channelFlags) { - for (uint i = 0; i < _CSTraits::channels_nb; i++) { - if ((int)i != _CSTraits::alpha_pos && (allChannelFlags || channelFlags.testBit(i))) { - composite_type unitValue = KoColorSpaceMathsTraits::unitValue; - composite_type invDst = unitValue - dst[i]; - - if(src[i] != KoColorSpaceMathsTraits::zeroValue) { - composite_type result = unitValue - qMin(invDst * unitValue / src[i], unitValue); - dst[i] = KoColorSpaceMaths::blend(result, dst[i], srcBlend); - } - else { - //composite_type result = KoColorSpaceMathsTraits::zeroValue; - composite_type result = unitValue - qMin(invDst * unitValue, unitValue); - dst[i] = KoColorSpaceMaths::blend(result, dst[i], srcBlend); + inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, + channels_type* dst, channels_type dstAlpha, + channels_type opacity, const QBitArray& channelFlags) { + srcAlpha = mul(srcAlpha, opacity); + + channels_type newDstAlpha = unionShapeOpacy(srcAlpha, dstAlpha); + + if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { + for(qint32 i=0; i ); + dst[i] = div(result, newDstAlpha); } } } + + return newDstAlpha; } - }; #endif diff --git a/libs/pigment/compositeops/KoCompositeOpDodge.h b/libs/pigment/compositeops/KoCompositeOpDodge.h index 368a26b..019695a 100644 --- a/libs/pigment/compositeops/KoCompositeOpDodge.h +++ b/libs/pigment/compositeops/KoCompositeOpDodge.h @@ -1,6 +1,7 @@ /* * 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 @@ -20,44 +21,40 @@ #ifndef _KOCOMPOSITEOPDODGE_H_ #define _KOCOMPOSITEOPDODGE_H_ -#include "KoCompositeOpAlphaBase.h" - +#include "KoCompositeOpFunctions.h" /** * A template version of the dodge composite operation to use in colorspaces. */ template -class KoCompositeOpDodge : public KoCompositeOpAlphaBase<_CSTraits, KoCompositeOpDodge<_CSTraits>, true > +class KoCompositeOpDodge : public KoCompositeOpBase< _CSTraits, KoCompositeOpDodge<_CSTraits> > { typedef typename _CSTraits::channels_type channels_type; - typedef typename KoColorSpaceMathsTraits::compositetype compositetype; + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + static const qint32 channels_nb = _CSTraits::channels_nb; + static const qint32 alpha_pos = _CSTraits::alpha_pos; public: - KoCompositeOpDodge(const KoColorSpace * cs) - : KoCompositeOpAlphaBase<_CSTraits, KoCompositeOpDodge<_CSTraits>, true >(cs, COMPOSITE_DODGE, i18n("Dodge"), KoCompositeOp::categoryLight()) { - } + : KoCompositeOpBase< _CSTraits, KoCompositeOpDodge<_CSTraits> >(cs, COMPOSITE_DODGE, i18n("Dodge"), KoCompositeOp::categoryLight()) { } public: - inline static channels_type selectAlpha(channels_type srcAlpha, channels_type dstAlpha) { - return qMin(srcAlpha, dstAlpha); - } - inline static void composeColorChannels(channels_type srcBlend, - const channels_type* src, - channels_type* dst, - bool allChannelFlags, - const QBitArray & channelFlags) { - for (uint channel = 0; channel < _CSTraits::channels_nb; channel++) { - if ((int)channel != _CSTraits::alpha_pos && (allChannelFlags || channelFlags.testBit(channel))) { - compositetype srcColor = src[channel]; - compositetype dstColor = dst[channel]; - - srcColor = qMin((compositetype)(dstColor * (NATIVE_MAX_VALUE + 1)) / (NATIVE_MAX_VALUE + 1 - srcColor), (compositetype)NATIVE_MAX_VALUE); - - channels_type newColor = KoColorSpaceMaths::blend(srcColor, dstColor, srcBlend); - - dst[channel] = newColor; + inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, + channels_type* dst, channels_type dstAlpha, + channels_type opacity, const QBitArray& channelFlags) { + srcAlpha = mul(srcAlpha, opacity); + + channels_type newDstAlpha = unionShapeOpacy(srcAlpha, dstAlpha); + + if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { + for(qint32 i=0; i ); + dst[i] = div(result, newDstAlpha); + } } } + + return newDstAlpha; } }; diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h new file mode 100644 index 0000000..bdd3af7 --- /dev/null +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -0,0 +1,193 @@ +/* + * 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 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 KOCOMPOSITEOPFUNCTIONS_H_ +#define KOCOMPOSITEOPFUNCTIONS_H_ + +#include +#include +#include + +/* --------------------- Arithmetic functions ----------------------------- / + * definitions of standard arithmetic functions. all computations are meant + * to be performed on normalized values (in the range of 0.0 - 1.0) + * if non floating point types are used, fixed point arithmetic is used + */ + +template +inline T mul(T a, T b) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + return T(composite_type(a) * composite_type(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 typename KoColorSpaceMathsTraits::compositetype +div(T a, T b) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + return composite_type(a) * KoColorSpaceMathsTraits::unitValue / composite_type(b); +} + +template +inline T inv(T a) { + return KoColorSpaceMathsTraits::unitValue - a; +} + +template +inline T clamp(typename KoColorSpaceMathsTraits::compositetype a) { + return (a > KoColorSpaceMathsTraits::unitValue) ? KoColorSpaceMathsTraits::unitValue : T(a); +} + +template +inline T lerp(T a, T b, T alpha) { + return KoColorSpaceMaths::blend(b, a, alpha); +} + +template +inline TRet scale(T a) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + return TRet(composite_type(a) * KoColorSpaceMathsTraits::unitValue / KoColorSpaceMathsTraits::unitValue); +} + +/* ---------------- Blending/Compositing functions ------------------------ / + * definitions of standard blending/compositing functions compatible + * to the ISO 32000-1 specification (for PDF filed) which also defines + * the compositing functions who are also used in Adobe Photoshop (c) + */ + +template +inline T unionShapeOpacy(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, TFunc blendFunc) { + return mul(inv(srcAlpha), dstAlpha, dst) + mul(inv(dstAlpha), srcAlpha, src) + mul(dstAlpha, srcAlpha, blendFunc(src, dst)); +} + +template +inline T cfColorBurn(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + + if(src != KoColorSpaceMathsTraits::zeroValue) + return inv(clamp(div(inv(dst), src))); + + return KoColorSpaceMathsTraits::zeroValue; +} + +template +inline T cfColorDodge(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + + if(src != KoColorSpaceMathsTraits::unitValue) + return clamp(div(dst, inv(src))); + + return KoColorSpaceMathsTraits::unitValue; +} + +/** + * A template base class that can be used for most composite modes/ops + * + * @param _compositeOp this template parameter is a class that must be + * derived fom KoCompositeOpBase and must define the static member function + * inline static channels_type composeColorChannels( + * const channels_type* src, + * channels_type srcAlpha, + * channels_type* dst, + * channels_type dstAlpha, + * channels_type opacity, + * const QBitArray& channelFlags + * ) + * + * where channels_type is _CSTraits::channels_type + */ +template +class KoCompositeOpBase : public KoCompositeOp +{ + typedef typename _CSTraits::channels_type channels_type; + static const qint32 channels_nb = _CSTraits::channels_nb; + static const qint32 alpha_pos = _CSTraits::alpha_pos; + +public: + + KoCompositeOpBase(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category) + : KoCompositeOp(cs, id, description, category) { } + +private: + template + void genericComposite(quint8* dstRowStart , qint32 dstRowStride , + const quint8* srcRowStart , qint32 srcRowStride , + const quint8* maskRowStart, qint32 maskRowStride, + qint32 rows, qint32 cols, quint8 U8_opacity, const QBitArray& channelFlags) const { + + qint32 srcInc = (srcRowStride == 0) ? 0 : channels_nb; + bool useMask = maskRowStart != 0; + channels_type unitValue = KoColorSpaceMathsTraits::unitValue; + channels_type opacity = KoColorSpaceMaths::scaleToA(U8_opacity); + + for(; rows>0; --rows) { + const channels_type* src = reinterpret_cast(srcRowStart); + channels_type* dst = reinterpret_cast(dstRowStart); + const quint8* mask = maskRowStart; + + for(qint32 c=cols; c>0; --c) { + channels_type srcAlpha = (alpha_pos == -1) ? unitValue : src[alpha_pos]; + channels_type dstAlpha = (alpha_pos == -1) ? unitValue : dst[alpha_pos]; + channels_type blend = useMask ? mul(opacity, scale(*mask)) : opacity; + channels_type newDstAlpha = _compositeOp::composeColorChannels(src, srcAlpha, dst, dstAlpha, blend, channelFlags); + + if(alpha_pos != -1) + dst[alpha_pos] = alphaLocked ? dstAlpha : newDstAlpha; + + src += srcInc; + dst += channels_nb; + ++mask; + } + + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + maskRowStart += maskRowStride; + } + } + +public: + using KoCompositeOp::composite; + + virtual void composite(quint8* dstRowStart , qint32 dstRowStride , + const quint8* srcRowStart , qint32 srcRowStride , + const quint8* maskRowStart, qint32 maskRowStride, + qint32 rows, qint32 cols, quint8 U8_opacity, const QBitArray& channelFlags) const { + + const QBitArray& flags = channelFlags.isEmpty() ? QBitArray(channels_nb,true) : channelFlags; + bool alphaLocked = (alpha_pos != -1) && !flags.testBit(alpha_pos); + + if(alphaLocked) + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + else + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + } +}; + +#endif // KOCOMPOSITEOPFUNCTIONS_H_ -- 1.7.1 From 5ac8037cee855175f8448b9671b00db9d876f3dc Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Sat, 8 Jan 2011 03:46:10 +0100 Subject: [PATCH 03/15] Added KoCompositeOpGeneric class to easily create new composite modes by just defining a composition function. The KoCompositeOpGeneric class is a template that takes a function pointer to a composition function as a second template parameter. So for the most composition modes it is not needed anymore to derive a new class from KoCompositionOp (or from one of its derivates) --- libs/pigment/KoCompositeOp.h | 2 + libs/pigment/compositeops/KoCompositeOpBurn.h | 2 +- libs/pigment/compositeops/KoCompositeOpDodge.h | 2 +- libs/pigment/compositeops/KoCompositeOpFunctions.h | 64 +++++++++++++++++--- libs/pigment/compositeops/KoCompositeOpGeneric.h | 65 ++++++++++++++++++++ libs/pigment/compositeops/KoCompositeOps.h | 56 +++++++++++------ 6 files changed, 162 insertions(+), 29 deletions(-) create mode 100644 libs/pigment/compositeops/KoCompositeOpGeneric.h diff --git a/libs/pigment/KoCompositeOp.h b/libs/pigment/KoCompositeOp.h index f6fb236..73c923e 100644 --- a/libs/pigment/KoCompositeOp.h +++ b/libs/pigment/KoCompositeOp.h @@ -43,7 +43,9 @@ const QString COMPOSITE_DIFF = "diff"; const QString COMPOSITE_MULT = "multiply"; const QString COMPOSITE_DIVIDE = "divide"; const QString COMPOSITE_DODGE = "dodge"; +const QString COMPOSITE_LINEAR_DODGE = "linear_dodge"; const QString COMPOSITE_BURN = "burn"; +const QString COMPOSITE_LINEAR_BURN = "linear_burn"; const QString COMPOSITE_BUMPMAP = "bumpmap"; const QString COMPOSITE_CLEAR = "clear"; const QString COMPOSITE_DISSOLVE = "dissolve"; diff --git a/libs/pigment/compositeops/KoCompositeOpBurn.h b/libs/pigment/compositeops/KoCompositeOpBurn.h index 3315373..857efea 100644 --- a/libs/pigment/compositeops/KoCompositeOpBurn.h +++ b/libs/pigment/compositeops/KoCompositeOpBurn.h @@ -35,7 +35,7 @@ class KoCompositeOpBurn : public KoCompositeOpBase< _CSTraits, KoCompositeOpBurn public: KoCompositeOpBurn(const KoColorSpace* cs) - : KoCompositeOpBase< _CSTraits, KoCompositeOpBurn<_CSTraits> >(cs, COMPOSITE_BURN, i18n("Burn"), KoCompositeOp::categoryLight()) { } + : KoCompositeOpBase< _CSTraits, KoCompositeOpBurn<_CSTraits> >(cs, COMPOSITE_BURN, i18n("Burn"), KoCompositeOp::categoryLight(), true) { } public: inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, diff --git a/libs/pigment/compositeops/KoCompositeOpDodge.h b/libs/pigment/compositeops/KoCompositeOpDodge.h index 019695a..815d273 100644 --- a/libs/pigment/compositeops/KoCompositeOpDodge.h +++ b/libs/pigment/compositeops/KoCompositeOpDodge.h @@ -35,7 +35,7 @@ class KoCompositeOpDodge : public KoCompositeOpBase< _CSTraits, KoCompositeOpDod static const qint32 alpha_pos = _CSTraits::alpha_pos; public: KoCompositeOpDodge(const KoColorSpace * cs) - : KoCompositeOpBase< _CSTraits, KoCompositeOpDodge<_CSTraits> >(cs, COMPOSITE_DODGE, i18n("Dodge"), KoCompositeOp::categoryLight()) { } + : KoCompositeOpBase< _CSTraits, KoCompositeOpDodge<_CSTraits> >(cs, COMPOSITE_DODGE, i18n("Dodge"), KoCompositeOp::categoryLight(), true) { } public: inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index bdd3af7..0656fa5 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -56,7 +56,8 @@ inline T inv(T a) { template inline T clamp(typename KoColorSpaceMathsTraits::compositetype a) { - return (a > KoColorSpaceMathsTraits::unitValue) ? KoColorSpaceMathsTraits::unitValue : T(a); + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + return qBound(KoColorSpaceMathsTraits::zeroValue, a, KoColorSpaceMathsTraits::unitValue); } template @@ -89,24 +90,69 @@ inline T blend(T src, T srcAlpha, T dst, T dstAlpha, TFunc blendFunc) { template inline T cfColorBurn(T src, T dst) { - typedef typename KoColorSpaceMathsTraits::compositetype composite_type; - if(src != KoColorSpaceMathsTraits::zeroValue) return inv(clamp(div(inv(dst), src))); - return KoColorSpaceMathsTraits::zeroValue; } template -inline T cfColorDodge(T src, T dst) { +inline T cfLinearBurn(T src, T dst) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; - + return clamp(composite_type(src) + dst - KoColorSpaceMathsTraits::unitValue); +} + +template +inline T cfColorDodge(T src, T dst) { if(src != KoColorSpaceMathsTraits::unitValue) return clamp(div(dst, inv(src))); - return KoColorSpaceMathsTraits::unitValue; } +template +inline T cfAddition(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + return clamp(composite_type(src) + dst); +} + +template +inline T cfSubtract(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + return clamp(composite_type(dst) - src); +} + +template +inline T cfExclusion(T src, T dst) { + 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) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + if(src == KoColorSpaceMathsTraits::zeroValue) + return dst; + return clamp(div(dst, src)); +} + +template +inline T cfOver(T src, T dst) { Q_UNUSED(dst); return src; } + +template +inline T cfMultiply(T src, T dst) { return mul(src, dst); } + +template +inline T cfDifference(T src, T dst) { return qMax(src,dst) - qMin(src,dst); } + +template +inline T cfScreen(T src, T dst) { return unionShapeOpacy(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); } + /** * A template base class that can be used for most composite modes/ops * @@ -132,8 +178,8 @@ class KoCompositeOpBase : public KoCompositeOp public: - KoCompositeOpBase(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category) - : KoCompositeOp(cs, id, description, category) { } + KoCompositeOpBase(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible) + : KoCompositeOp(cs, id, description, category, userVisible) { } private: template diff --git a/libs/pigment/compositeops/KoCompositeOpGeneric.h b/libs/pigment/compositeops/KoCompositeOpGeneric.h new file mode 100644 index 0000000..805b017 --- /dev/null +++ b/libs/pigment/compositeops/KoCompositeOpGeneric.h @@ -0,0 +1,65 @@ +/* + * 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 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 _KOCOMPOSITEO_GENERIC_H_ +#define _KOCOMPOSITEO_GENERIC_H_ + +#include "KoCompositeOpFunctions.h" + +/** + * A template version of the burn composite operation to use in colorspaces. + */ +template< + class Traits, + typename Traits::channels_type compositeFunc(typename Traits::channels_type, typename Traits::channels_type) +> +class KoCompositeOpGeneric : public KoCompositeOpBase< Traits, KoCompositeOpGeneric > +{ + typedef KoCompositeOpBase< Traits, KoCompositeOpGeneric > base_class; + typedef typename Traits::channels_type channels_type; + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + + static const qint32 channels_nb = Traits::channels_nb; + static const qint32 alpha_pos = Traits::alpha_pos; + +public: + KoCompositeOpGeneric(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) + : base_class(cs, id, description, category, userVisible) { } + +public: + inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, + channels_type* dst, channels_type dstAlpha, + channels_type opacity, const QBitArray& channelFlags) { + srcAlpha = mul(srcAlpha, opacity); + channels_type newDstAlpha = unionShapeOpacy(srcAlpha, dstAlpha); + + if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { + for(qint32 i=0; i + * 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 @@ -22,21 +23,22 @@ #include "KoColorSpace.h" -#include "compositeops/KoCompositeOpAdd.h" +// #include "compositeops/KoCompositeOpAdd.h" #include "compositeops/KoCompositeOpAlphaDarken.h" -#include "compositeops/KoCompositeOpBurn.h" +// #include "compositeops/KoCompositeOpBurn.h" #include "compositeops/KoCompositeOpDivide.h" -#include "compositeops/KoCompositeOpDodge.h" +// #include "compositeops/KoCompositeOpDodge.h" #include "compositeops/KoCompositeOpErase.h" -#include "compositeops/KoCompositeOpMultiply.h" -#include "compositeops/KoCompositeOpOver.h" +// #include "compositeops/KoCompositeOpMultiply.h" +// #include "compositeops/KoCompositeOpOver.h" #include "compositeops/KoCompositeOpOverlay.h" -#include "compositeops/KoCompositeOpScreen.h" -#include "compositeops/KoCompositeOpSubtract.h" +// #include "compositeops/KoCompositeOpScreen.h" +// #include "compositeops/KoCompositeOpSubtract.h" #include "compositeops/KoCompositeOpInversedSubtract.h" #include "compositeops/KoCompositeOpSoftlight.h" #include "compositeops/KoCompositeOpHardlight.h" #include "compositeops/KoCompositeOpCopy2.h" +#include "compositeops/KoCompositeOpGeneric.h" /** * This function add to the colorspace all the composite ops defined by @@ -45,20 +47,38 @@ template void addStandardCompositeOps(KoColorSpace* cs) { - cs->addCompositeOp(new KoCompositeOpAdd<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpAdd<_Traits_>(cs)); cs->addCompositeOp(new KoCompositeOpAlphaDarken<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpBurn<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpBurn<_Traits_>(cs)); cs->addCompositeOp(new KoCompositeOpCopy2<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpDivide<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpDodge<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpDivide<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpDodge<_Traits_>(cs)); cs->addCompositeOp(new KoCompositeOpErase<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpMultiply<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpOver<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpOverlay<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpScreen<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpSubtract<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpSoftlight<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpHardlight<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpMultiply<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpOver<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpOverlay<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpScreen<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpSubtract<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpSoftlight<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpHardlight<_Traits_>(cs)); + + typedef typename _Traits_::channels_type type; + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOver >(cs, COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix())); + + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorBurn >(cs, COMPOSITE_BURN , i18n("Color Burn"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorDodge >(cs, COMPOSITE_DODGE , i18n("Color Dodge"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLinearBurn >(cs, COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDarkenOnly >(cs, COMPOSITE_DARKEN , i18n("Darken"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLightenOnly >(cs, COMPOSITE_LIGHTEN , i18n("Lighten"), KoCompositeOp::categoryLight())); + + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_ADD , i18n("Addition"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract >(cs, COMPOSITE_SUBTRACT , i18n("Subtract"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference >(cs, COMPOSITE_DIFF , i18n("Difference"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply >(cs, COMPOSITE_MULT , i18n("Multiply"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide >(cs, COMPOSITE_DIVIDE , i18n("Divide"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion >(cs, COMPOSITE_EXCLUSION, i18n("Exclusion"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen >(cs, COMPOSITE_SCREEN , i18n("Screen"), KoCompositeOp::categoryArithmetic())); } #endif -- 1.7.1 From 2dec28d893b4f63e21f76b8039a4dd9ab236c1bc Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Sat, 8 Jan 2011 03:54:09 +0100 Subject: [PATCH 04/15] Enable the Soft Light and Hard Light CompositeOps again. --- libs/pigment/compositeops/KoCompositeOps.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h index 7949865..b662f3a 100644 --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -59,8 +59,8 @@ void addStandardCompositeOps(KoColorSpace* cs) //cs->addCompositeOp(new KoCompositeOpOverlay<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpScreen<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpSubtract<_Traits_>(cs)); - //cs->addCompositeOp(new KoCompositeOpSoftlight<_Traits_>(cs)); - //cs->addCompositeOp(new KoCompositeOpHardlight<_Traits_>(cs)); + cs->addCompositeOp(new KoCompositeOpSoftlight<_Traits_>(cs)); + cs->addCompositeOp(new KoCompositeOpHardlight<_Traits_>(cs)); typedef typename _Traits_::channels_type type; cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOver >(cs, COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix())); -- 1.7.1 From 924c71e117c2f7ffb3151b2211fc6b7cd16f2b77 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Sat, 8 Jan 2011 13:09:59 +0100 Subject: [PATCH 05/15] Reset the Burn and Dodge CompositeOps files to their original state. This files are not needed anymore KoCompositeOpGeneric is used instead --- libs/pigment/compositeops/KoCompositeOpBurn.h | 52 +++++++++++++---------- libs/pigment/compositeops/KoCompositeOpDodge.h | 49 ++++++++++++---------- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/libs/pigment/compositeops/KoCompositeOpBurn.h b/libs/pigment/compositeops/KoCompositeOpBurn.h index 857efea..97feaa4 100644 --- a/libs/pigment/compositeops/KoCompositeOpBurn.h +++ b/libs/pigment/compositeops/KoCompositeOpBurn.h @@ -20,42 +20,48 @@ #ifndef KOCOMPOSITEOPBURN_H_ #define KOCOMPOSITEOPBURN_H_ -#include "KoCompositeOpFunctions.h" +#include "KoCompositeOpAlphaBase.h" /** * A template version of the burn composite operation to use in colorspaces. */ template -class KoCompositeOpBurn : public KoCompositeOpBase< _CSTraits, KoCompositeOpBurn<_CSTraits> > +class KoCompositeOpBurn : public KoCompositeOpAlphaBase<_CSTraits, KoCompositeOpBurn<_CSTraits>, true > { typedef typename _CSTraits::channels_type channels_type; - typedef typename KoColorSpaceMathsTraits::compositetype composite_type; - static const qint32 channels_nb = _CSTraits::channels_nb; - static const qint32 alpha_pos = _CSTraits::alpha_pos; - + typedef typename KoColorSpaceMathsTraits::compositetype compositetype; public: - KoCompositeOpBurn(const KoColorSpace* cs) - : KoCompositeOpBase< _CSTraits, KoCompositeOpBurn<_CSTraits> >(cs, COMPOSITE_BURN, i18n("Burn"), KoCompositeOp::categoryLight(), true) { } + + KoCompositeOpBurn(const KoColorSpace * cs) + : KoCompositeOpAlphaBase<_CSTraits, KoCompositeOpBurn<_CSTraits>, true >(cs, COMPOSITE_BURN, i18n("Burn"), KoCompositeOp::categoryLight()) { + } public: - inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, - channels_type* dst, channels_type dstAlpha, - channels_type opacity, const QBitArray& channelFlags) { - srcAlpha = mul(srcAlpha, opacity); - - channels_type newDstAlpha = unionShapeOpacy(srcAlpha, dstAlpha); - - if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { - for(qint32 i=0; i ); - dst[i] = div(result, newDstAlpha); - } + inline static channels_type selectAlpha(channels_type srcAlpha, channels_type dstAlpha) { + return qMin(srcAlpha, dstAlpha); + } + + inline static void composeColorChannels(channels_type srcBlend, + const channels_type* src, + channels_type* dst, + bool allChannelFlags, + const QBitArray & channelFlags) { + for (uint i = 0; i < _CSTraits::channels_nb; i++) { + if ((int)i != _CSTraits::alpha_pos && (allChannelFlags || channelFlags.testBit(i))) { + compositetype srcColor = src[i]; + compositetype dstColor = dst[i]; + + srcColor = qMin(((NATIVE_MAX_VALUE - dstColor) * (NATIVE_MAX_VALUE + 1)) / (srcColor + 1), (compositetype)NATIVE_MAX_VALUE); + if (NATIVE_MAX_VALUE - srcColor > NATIVE_MAX_VALUE) srcColor = NATIVE_MAX_VALUE; + + channels_type newColor = NATIVE_MAX_VALUE - KoColorSpaceMaths::blend(srcColor, dstColor, srcBlend); + + dst[i] = newColor; } } - - return newDstAlpha; } + + }; #endif diff --git a/libs/pigment/compositeops/KoCompositeOpDodge.h b/libs/pigment/compositeops/KoCompositeOpDodge.h index 815d273..368a26b 100644 --- a/libs/pigment/compositeops/KoCompositeOpDodge.h +++ b/libs/pigment/compositeops/KoCompositeOpDodge.h @@ -1,7 +1,6 @@ /* * 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 @@ -21,40 +20,44 @@ #ifndef _KOCOMPOSITEOPDODGE_H_ #define _KOCOMPOSITEOPDODGE_H_ -#include "KoCompositeOpFunctions.h" +#include "KoCompositeOpAlphaBase.h" + /** * A template version of the dodge composite operation to use in colorspaces. */ template -class KoCompositeOpDodge : public KoCompositeOpBase< _CSTraits, KoCompositeOpDodge<_CSTraits> > +class KoCompositeOpDodge : public KoCompositeOpAlphaBase<_CSTraits, KoCompositeOpDodge<_CSTraits>, true > { typedef typename _CSTraits::channels_type channels_type; - typedef typename KoColorSpaceMathsTraits::compositetype composite_type; - static const qint32 channels_nb = _CSTraits::channels_nb; - static const qint32 alpha_pos = _CSTraits::alpha_pos; + typedef typename KoColorSpaceMathsTraits::compositetype compositetype; public: + KoCompositeOpDodge(const KoColorSpace * cs) - : KoCompositeOpBase< _CSTraits, KoCompositeOpDodge<_CSTraits> >(cs, COMPOSITE_DODGE, i18n("Dodge"), KoCompositeOp::categoryLight(), true) { } + : KoCompositeOpAlphaBase<_CSTraits, KoCompositeOpDodge<_CSTraits>, true >(cs, COMPOSITE_DODGE, i18n("Dodge"), KoCompositeOp::categoryLight()) { + } public: - inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, - channels_type* dst, channels_type dstAlpha, - channels_type opacity, const QBitArray& channelFlags) { - srcAlpha = mul(srcAlpha, opacity); - - channels_type newDstAlpha = unionShapeOpacy(srcAlpha, dstAlpha); - - if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { - for(qint32 i=0; i ); - dst[i] = div(result, newDstAlpha); - } + inline static channels_type selectAlpha(channels_type srcAlpha, channels_type dstAlpha) { + return qMin(srcAlpha, dstAlpha); + } + inline static void composeColorChannels(channels_type srcBlend, + const channels_type* src, + channels_type* dst, + bool allChannelFlags, + const QBitArray & channelFlags) { + for (uint channel = 0; channel < _CSTraits::channels_nb; channel++) { + if ((int)channel != _CSTraits::alpha_pos && (allChannelFlags || channelFlags.testBit(channel))) { + compositetype srcColor = src[channel]; + compositetype dstColor = dst[channel]; + + srcColor = qMin((compositetype)(dstColor * (NATIVE_MAX_VALUE + 1)) / (NATIVE_MAX_VALUE + 1 - srcColor), (compositetype)NATIVE_MAX_VALUE); + + channels_type newColor = KoColorSpaceMaths::blend(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; } } - - return newDstAlpha; } }; -- 1.7.1 From 715a106a266b5b1fda71b1fd64acc2084f411483 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Sat, 8 Jan 2011 16:10:09 +0100 Subject: [PATCH 06/15] Added "Soft Light", "Hard Light" and "Overlay" blending functions. --- libs/pigment/KoColorSpaceMaths.cpp | 3 + libs/pigment/KoColorSpaceMaths.h | 7 ++ libs/pigment/compositeops/KoCompositeOpFunctions.h | 70 +++++++++++++++----- libs/pigment/compositeops/KoCompositeOps.h | 47 +++++++------ 4 files changed, 88 insertions(+), 39 deletions(-) diff --git a/libs/pigment/KoColorSpaceMaths.cpp b/libs/pigment/KoColorSpaceMaths.cpp index 891c8a2..b2f82ed 100644 --- a/libs/pigment/KoColorSpaceMaths.cpp +++ b/libs/pigment/KoColorSpaceMaths.cpp @@ -26,6 +26,7 @@ #ifdef HAVE_OPENEXR const half KoColorSpaceMathsTraits::zeroValue = 0.0; const half KoColorSpaceMathsTraits::unitValue = 1.0; +const half KoColorSpaceMathsTraits::halfValue = 0.5; const half KoColorSpaceMathsTraits::max = HALF_MAX; const half KoColorSpaceMathsTraits::min = -HALF_MAX; const half KoColorSpaceMathsTraits::epsilon = HALF_EPSILON; @@ -34,6 +35,7 @@ const KoChannelInfo::enumChannelValueType KoColorSpaceMathsTraits::channel const float KoColorSpaceMathsTraits::zeroValue = 0.0; const float KoColorSpaceMathsTraits::unitValue = 1.0; +const float KoColorSpaceMathsTraits::halfValue = 0.5; const float KoColorSpaceMathsTraits::max = FLT_MAX; const float KoColorSpaceMathsTraits::min = -FLT_MAX; const float KoColorSpaceMathsTraits::epsilon = FLT_EPSILON; @@ -41,6 +43,7 @@ const KoChannelInfo::enumChannelValueType KoColorSpaceMathsTraits::channe const double KoColorSpaceMathsTraits::zeroValue = 0.0; const double KoColorSpaceMathsTraits::unitValue = 1.0; +const double KoColorSpaceMathsTraits::halfValue = 0.5; const double KoColorSpaceMathsTraits::max = DBL_MAX; const double KoColorSpaceMathsTraits::min = -DBL_MAX; const double KoColorSpaceMathsTraits::epsilon = DBL_EPSILON; diff --git a/libs/pigment/KoColorSpaceMaths.h b/libs/pigment/KoColorSpaceMaths.h index a0ba9cf..f577a7d 100644 --- a/libs/pigment/KoColorSpaceMaths.h +++ b/libs/pigment/KoColorSpaceMaths.h @@ -56,6 +56,7 @@ 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; @@ -70,6 +71,7 @@ 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; @@ -84,6 +86,7 @@ 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; @@ -98,6 +101,7 @@ 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; @@ -116,6 +120,7 @@ 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; @@ -131,6 +136,7 @@ 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; @@ -145,6 +151,7 @@ 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; diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index 0656fa5..de41921 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -30,10 +30,16 @@ * if non floating point types are used, fixed point arithmetic is used */ +// template +// inline T mul(T a, T b) { T(KoColorSpaceMaths::multiply(a, b)); } + +// template +// inline T mul(T a, T b, T c) { T(KoColorSpaceMaths::multiply(a, b, c)); } + template inline T mul(T a, T b) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; - return T(composite_type(a) * composite_type(b) / KoColorSpaceMathsTraits::unitValue); + return T(composite_type(a) * b / KoColorSpaceMathsTraits::unitValue); } template @@ -43,6 +49,21 @@ inline T mul(T a, T b, T c) { } template +inline T inv(T a) { return KoColorSpaceMathsTraits::unitValue - 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 TRet scale(T a) { +// typedef typename KoColorSpaceMathsTraits::compositetype composite_type; +// return TRet(composite_type(a) * KoColorSpaceMathsTraits::unitValue / KoColorSpaceMathsTraits::unitValue); +// } + +template inline typename KoColorSpaceMathsTraits::compositetype div(T a, T b) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; @@ -50,27 +71,11 @@ div(T a, T b) { } template -inline T inv(T a) { - return KoColorSpaceMathsTraits::unitValue - a; -} - -template inline T clamp(typename KoColorSpaceMathsTraits::compositetype a) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; return qBound(KoColorSpaceMathsTraits::zeroValue, a, KoColorSpaceMathsTraits::unitValue); } -template -inline T lerp(T a, T b, T alpha) { - return KoColorSpaceMaths::blend(b, a, alpha); -} - -template -inline TRet scale(T a) { - typedef typename KoColorSpaceMathsTraits::compositetype composite_type; - return TRet(composite_type(a) * KoColorSpaceMathsTraits::unitValue / KoColorSpaceMathsTraits::unitValue); -} - /* ---------------- Blending/Compositing functions ------------------------ / * definitions of standard blending/compositing functions compatible * to the ISO 32000-1 specification (for PDF filed) which also defines @@ -136,9 +141,40 @@ inline T cfDivide(T src, T dst) { } template +inline T cfHardLight(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + composite_type src2 = composite_type(src) + src; + + if(src > KoColorSpaceMathsTraits::halfValue) { + // screen(src*2.0 - 1.0, dst) + src2 -= KoColorSpaceMathsTraits::unitValue; + return T((src2+dst) - (src2*dst / KoColorSpaceMathsTraits::unitValue)); + } + + // multiply(src*2.0, dst) + return clamp(src2*dst / KoColorSpaceMathsTraits::unitValue); +} + +template +inline T cfSoftLight(T src, T dst) { + 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 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 mul(src, dst); } template diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h index b662f3a..b563261 100644 --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -26,17 +26,17 @@ // #include "compositeops/KoCompositeOpAdd.h" #include "compositeops/KoCompositeOpAlphaDarken.h" // #include "compositeops/KoCompositeOpBurn.h" -#include "compositeops/KoCompositeOpDivide.h" +// #include "compositeops/KoCompositeOpDivide.h" // #include "compositeops/KoCompositeOpDodge.h" #include "compositeops/KoCompositeOpErase.h" // #include "compositeops/KoCompositeOpMultiply.h" // #include "compositeops/KoCompositeOpOver.h" -#include "compositeops/KoCompositeOpOverlay.h" +// #include "compositeops/KoCompositeOpOverlay.h" // #include "compositeops/KoCompositeOpScreen.h" // #include "compositeops/KoCompositeOpSubtract.h" -#include "compositeops/KoCompositeOpInversedSubtract.h" -#include "compositeops/KoCompositeOpSoftlight.h" -#include "compositeops/KoCompositeOpHardlight.h" +// #include "compositeops/KoCompositeOpInversedSubtract.h" +// #include "compositeops/KoCompositeOpSoftlight.h" +// #include "compositeops/KoCompositeOpHardlight.h" #include "compositeops/KoCompositeOpCopy2.h" #include "compositeops/KoCompositeOpGeneric.h" @@ -59,26 +59,29 @@ void addStandardCompositeOps(KoColorSpace* cs) //cs->addCompositeOp(new KoCompositeOpOverlay<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpScreen<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpSubtract<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpSoftlight<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpHardlight<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpSoftlight<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpHardlight<_Traits_>(cs)); - typedef typename _Traits_::channels_type type; - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOver >(cs, COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix())); + typedef typename _Traits_::channels_type T; + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOver >(cs, COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorBurn >(cs, COMPOSITE_BURN , i18n("Color Burn"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorDodge >(cs, COMPOSITE_DODGE , i18n("Color Dodge"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLinearBurn >(cs, COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDarkenOnly >(cs, COMPOSITE_DARKEN , i18n("Darken"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLightenOnly >(cs, COMPOSITE_LIGHTEN , i18n("Lighten"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorBurn >(cs, COMPOSITE_BURN , i18n("Color Burn"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorDodge >(cs, COMPOSITE_DODGE , i18n("Color Dodge"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLinearBurn >(cs, COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDarkenOnly >(cs, COMPOSITE_DARKEN , i18n("Darken"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLightenOnly >(cs, COMPOSITE_LIGHTEN , i18n("Lighten"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfHardLight >(cs, COMPOSITE_HARD_LIGHT , i18n("Hard Light"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSoftLight >(cs, COMPOSITE_SOFT_LIGHT , i18n("Soft Light"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_ADD , i18n("Addition"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract >(cs, COMPOSITE_SUBTRACT , i18n("Subtract"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference >(cs, COMPOSITE_DIFF , i18n("Difference"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply >(cs, COMPOSITE_MULT , i18n("Multiply"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide >(cs, COMPOSITE_DIVIDE , i18n("Divide"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion >(cs, COMPOSITE_EXCLUSION, i18n("Exclusion"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen >(cs, COMPOSITE_SCREEN , i18n("Screen"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen >(cs, COMPOSITE_SCREEN , i18n("Screen"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOverlay >(cs, COMPOSITE_OVERLAY , i18n("Overlay"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_ADD , i18n("Addition"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract >(cs, COMPOSITE_SUBTRACT , i18n("Subtract"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference >(cs, COMPOSITE_DIFF , i18n("Difference"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply >(cs, COMPOSITE_MULT , i18n("Multiply"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide >(cs, COMPOSITE_DIVIDE , i18n("Divide"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion >(cs, COMPOSITE_EXCLUSION, i18n("Exclusion"), KoCompositeOp::categoryArithmetic())); } #endif -- 1.7.1 From 0d5c4f5a717253575c961686eb61fc5b1b60cb8e Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Sat, 8 Jan 2011 22:28:43 +0100 Subject: [PATCH 07/15] Added more blending functions. Arcus Tangent, Gamma Light, Gamma Dark, Geometric Mean, Vivid Light and Pin Light --- libs/pigment/KoCompositeOp.h | 10 ++- libs/pigment/compositeops/KoCompositeOpFunctions.h | 60 ++++++++++++++++++++ libs/pigment/compositeops/KoCompositeOps.h | 22 +++++--- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/libs/pigment/KoCompositeOp.h b/libs/pigment/KoCompositeOp.h index 73c923e..6f84313 100644 --- a/libs/pigment/KoCompositeOp.h +++ b/libs/pigment/KoCompositeOp.h @@ -42,6 +42,8 @@ const QString COMPOSITE_INVERSED_SUBTRACT = "inversed_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_DODGE = "dodge"; const QString COMPOSITE_LINEAR_DODGE = "linear_dodge"; const QString COMPOSITE_BURN = "burn"; @@ -67,11 +69,13 @@ const QString COMPOSITE_COPY_BLUE = "copy_blue"; const QString COMPOSITE_COPY_OPACITY = "copy_opacity"; const QString COMPOSITE_HARD_LIGHT = "hard_light"; const QString COMPOSITE_SOFT_LIGHT = "soft_light"; -const QString COMPOSITE_EXCLUSION = "exclusion"; // XXX: not implemented anywhere yet +const QString COMPOSITE_GAMMA_LIGHT = "gamma_light"; +const QString COMPOSITE_GAMMA_DARK = "gamma_dark"; +const QString COMPOSITE_EXCLUSION = "exclusion"; const QString COMPOSITE_INVERTED_DIVIDE = "inverted_divide"; // XXX: not implemented anywhere yet -const QString COMPOSITE_VIVID_LIGHT = "vivid light"; // XXX: not implemented anywhere yet +const QString COMPOSITE_VIVID_LIGHT = "vivid_light"; const QString COMPOSITE_LINEAR_LIGHT = "linear light"; // XXX: not implemented anywhere yet -const QString COMPOSITE_PIN_LIGHT = "pin light"; // XXX: not implemented anywhere yet +const QString COMPOSITE_PIN_LIGHT = "pin_light"; const QString COMPOSITE_HARD_MIX = "hard mix"; // XXX: not implemented anywhere yet const QString COMPOSITE_PASS_THROUGH = "pass through"; // XXX: not implemented anywhere yet diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index de41921..ae45877 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -169,6 +169,66 @@ inline T cfSoftLight(T src, T dst) { } template +inline T cfVividLight(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + + if(src < KoColorSpaceMathsTraits::halfValue) { + if(src == KoColorSpaceMathsTraits::zeroValue) + return KoColorSpaceMathsTraits::zeroValue; //TODO: maybe better to return unitValue, must be verified + + // min(1,max(0,1-(1-dst) / (2*src))) + composite_type src2 = composite_type(src) + src; + composite_type dsti = inv(dst); + return clamp(KoColorSpaceMathsTraits::unitValue - (dsti * KoColorSpaceMathsTraits::unitValue / src2)); + } + + if(src == KoColorSpaceMathsTraits::unitValue) + return KoColorSpaceMathsTraits::unitValue; //TODO: maybe better to return zeroValue, must be verified + + // min(1,max(0, dst / (2*(1-src))) + composite_type srci2 = inv(src); + srci2 += srci2; + return clamp(composite_type(dst) * KoColorSpaceMathsTraits::unitValue / srci2); +} + +template +inline T cfPinLight(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + // TODO: verify that the formular 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-KoColorSpaceMathsTraits::unitValue, a); + return T(b); +} + +template +inline T cfArcTangent(T src, T dst) { + const static qreal pi = 3.14159265358979323846; + + if(dst == KoColorSpaceMathsTraits::zeroValue) + return (src == KoColorSpaceMathsTraits::zeroValue) ? + KoColorSpaceMathsTraits::zeroValue : KoColorSpaceMathsTraits::unitValue; + + return scale(2.0 * atan(scale(src) / scale(dst)) / pi); +} + +template +inline T cfGammaDark(T src, T dst) { + if(src == KoColorSpaceMathsTraits::zeroValue) + return KoColorSpaceMathsTraits::zeroValue; + + // power(dst, 1/src) + return scale(pow(scale(dst), 1.0/scale(src))); +} + +template +inline T cfGammaLight(T src, T dst) { return scale(pow(scale(dst), scale(src))); } + +template +inline T cfGeometricMean(T src, T dst) { return scale(sqrt(scale(dst) * scale(src))); } + +template inline T cfOver(T src, T dst) { Q_UNUSED(dst); return src; } template diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h index b563261..000d2f8 100644 --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -73,15 +73,21 @@ void addStandardCompositeOps(KoColorSpace* cs) cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLightenOnly >(cs, COMPOSITE_LIGHTEN , i18n("Lighten"), KoCompositeOp::categoryLight())); cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfHardLight >(cs, COMPOSITE_HARD_LIGHT , i18n("Hard Light"), KoCompositeOp::categoryLight())); cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSoftLight >(cs, COMPOSITE_SOFT_LIGHT , i18n("Soft Light"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGammaLight >(cs, COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGammaDark >(cs, COMPOSITE_GAMMA_DARK , i18n("Gamma Dark"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfVividLight >(cs, COMPOSITE_VIVID_LIGHT , i18n("Vivid Light"), KoCompositeOp::categoryLight())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfPinLight >(cs, COMPOSITE_PIN_LIGHT , i18n("Pin Light"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen >(cs, COMPOSITE_SCREEN , i18n("Screen"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOverlay >(cs, COMPOSITE_OVERLAY , i18n("Overlay"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_ADD , i18n("Addition"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract >(cs, COMPOSITE_SUBTRACT , i18n("Subtract"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference >(cs, COMPOSITE_DIFF , i18n("Difference"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply >(cs, COMPOSITE_MULT , i18n("Multiply"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide >(cs, COMPOSITE_DIVIDE , i18n("Divide"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion >(cs, COMPOSITE_EXCLUSION, i18n("Exclusion"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen >(cs, COMPOSITE_SCREEN , i18n("Screen"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOverlay >(cs, COMPOSITE_OVERLAY , i18n("Overlay"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_ADD , i18n("Addition"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract >(cs, COMPOSITE_SUBTRACT , i18n("Subtract"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference >(cs, COMPOSITE_DIFF , i18n("Difference"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply >(cs, COMPOSITE_MULT , i18n("Multiply"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide >(cs, COMPOSITE_DIVIDE , i18n("Divide"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion >(cs, COMPOSITE_EXCLUSION , i18n("Exclusion"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfArcTangent >(cs, COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent"), KoCompositeOp::categoryArithmetic())); + cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGeometricMean >(cs, COMPOSITE_GEOMETRIC_MEAN, i18n("Geometric Mean"), KoCompositeOp::categoryArithmetic())); } #endif -- 1.7.1 From b8fe6518c15dc1d9fb13b65769d743d2cdeb886e Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Sat, 8 Jan 2011 23:09:42 +0100 Subject: [PATCH 08/15] Added more constant expressions. This should make it easier for the compiler to "optimize things away" (in theory). If the compiler really will produce faster code, only knows the compiler :P --- libs/pigment/compositeops/KoCompositeOpFunctions.h | 52 +++++++++++++------ libs/pigment/compositeops/KoCompositeOpGeneric.h | 5 +- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index ae45877..25e5112 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -76,10 +76,9 @@ inline T clamp(typename KoColorSpaceMathsTraits::compositetype a) { return qBound(KoColorSpaceMathsTraits::zeroValue, a, KoColorSpaceMathsTraits::unitValue); } -/* ---------------- Blending/Compositing functions ------------------------ / - * definitions of standard blending/compositing functions compatible - * to the ISO 32000-1 specification (for PDF filed) which also defines - * the compositing functions who are also used in Adobe Photoshop (c) +/* ------------------------ Auxiliary Functions --------------------------- / + * definitions of auxiliary functions needed by the blending functions + * or the KoCompositeOp* classes to calculate the pixel colors */ template @@ -88,11 +87,17 @@ inline T unionShapeOpacy(T a, T b) { return T(composite_type(a) + b - mul(a,b)); } -template -inline T blend(T src, T srcAlpha, T dst, T dstAlpha, TFunc blendFunc) { +template +inline T blend(T src, T srcAlpha, T dst, T dstAlpha) { return mul(inv(srcAlpha), dstAlpha, dst) + mul(inv(dstAlpha), srcAlpha, src) + mul(dstAlpha, srcAlpha, blendFunc(src, dst)); } +/* ---------------- Blending/Compositing functions ------------------------ / + * definitions of standard blending/compositing functions compatible + * to the ISO 32000-1 specification (for PDF filed) which also defines + * the compositing functions who are also used in Adobe Photoshop (c) + */ + template inline T cfColorBurn(T src, T dst) { if(src != KoColorSpaceMathsTraits::zeroValue) @@ -254,6 +259,7 @@ inline T cfLightenOnly(T src, T dst) { return qMax(src, dst); } * * @param _compositeOp this template parameter is a class that must be * derived fom KoCompositeOpBase and must define the static member function + * template * inline static channels_type composeColorChannels( * const channels_type* src, * channels_type srcAlpha, @@ -278,7 +284,7 @@ public: : KoCompositeOp(cs, id, description, category, userVisible) { } private: - template + template void genericComposite(quint8* dstRowStart , qint32 dstRowStride , const quint8* srcRowStart , qint32 srcRowStride , const quint8* maskRowStart, qint32 maskRowStride, @@ -295,10 +301,13 @@ private: const quint8* mask = maskRowStart; for(qint32 c=cols; c>0; --c) { - channels_type srcAlpha = (alpha_pos == -1) ? unitValue : src[alpha_pos]; - channels_type dstAlpha = (alpha_pos == -1) ? unitValue : dst[alpha_pos]; - channels_type blend = useMask ? mul(opacity, scale(*mask)) : opacity; - channels_type newDstAlpha = _compositeOp::composeColorChannels(src, srcAlpha, dst, dstAlpha, blend, channelFlags); + channels_type srcAlpha = (alpha_pos == -1) ? unitValue : src[alpha_pos]; + channels_type dstAlpha = (alpha_pos == -1) ? unitValue : dst[alpha_pos]; + channels_type blend = useMask ? mul(opacity, scale(*mask)) : opacity; + + channels_type newDstAlpha = _compositeOp::template composeColorChannels( + src, srcAlpha, dst, dstAlpha, blend, channelFlags + ); if(alpha_pos != -1) dst[alpha_pos] = alphaLocked ? dstAlpha : newDstAlpha; @@ -322,13 +331,22 @@ public: const quint8* maskRowStart, qint32 maskRowStride, qint32 rows, qint32 cols, quint8 U8_opacity, const QBitArray& channelFlags) const { - const QBitArray& flags = channelFlags.isEmpty() ? QBitArray(channels_nb,true) : channelFlags; - bool alphaLocked = (alpha_pos != -1) && !flags.testBit(alpha_pos); + const QBitArray& flags = channelFlags.isEmpty() ? QBitArray(channels_nb,true) : channelFlags; + bool allChannelFlags = channelFlags.isEmpty(); + bool alphaLocked = (alpha_pos != -1) && !flags.testBit(alpha_pos); - if(alphaLocked) - genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); - else - genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + if(alphaLocked) { + if(allChannelFlags) + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + else + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + } + else { + if(allChannelFlags) + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + else + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + } } }; diff --git a/libs/pigment/compositeops/KoCompositeOpGeneric.h b/libs/pigment/compositeops/KoCompositeOpGeneric.h index 805b017..92ca590 100644 --- a/libs/pigment/compositeops/KoCompositeOpGeneric.h +++ b/libs/pigment/compositeops/KoCompositeOpGeneric.h @@ -43,6 +43,7 @@ public: : base_class(cs, id, description, category, userVisible) { } public: + template inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, channels_type* dst, channels_type dstAlpha, channels_type opacity, const QBitArray& channelFlags) { @@ -51,8 +52,8 @@ public: if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { for(qint32 i=0; i (src[i], srcAlpha, dst[i], dstAlpha); dst[i] = div(result, newDstAlpha); } } -- 1.7.1 From ced395ab1047797c28d8cd0a9a70132bcd588fc4 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Sun, 9 Jan 2011 17:57:18 +0100 Subject: [PATCH 09/15] Added even more composite modes. Including HSL composite modes (Color, Saturation, Luminosity, Hue). The HSL CompositeOps will only be added to RGB color spaces. --- libs/pigment/KoCompositeOp.h | 5 +- libs/pigment/compositeops/KoCompositeOpFunctions.h | 214 +++++++++++++++++++- libs/pigment/compositeops/KoCompositeOpGeneric.h | 2 +- libs/pigment/compositeops/KoCompositeOps.h | 135 ++++++++++--- 4 files changed, 316 insertions(+), 40 deletions(-) diff --git a/libs/pigment/KoCompositeOp.h b/libs/pigment/KoCompositeOp.h index 6f84313..920fe3e 100644 --- a/libs/pigment/KoCompositeOp.h +++ b/libs/pigment/KoCompositeOp.h @@ -43,11 +43,14 @@ 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_EQUIVALENCE = "equivalence"; const QString COMPOSITE_GEOMETRIC_MEAN = "geometric_mean"; const QString COMPOSITE_DODGE = "dodge"; const QString COMPOSITE_LINEAR_DODGE = "linear_dodge"; const QString COMPOSITE_BURN = "burn"; const QString COMPOSITE_LINEAR_BURN = "linear_burn"; +const QString COMPOSITE_ALLANON = "allanon"; +const QString COMPOSITE_PARALLEL = "parallel"; const QString COMPOSITE_BUMPMAP = "bumpmap"; const QString COMPOSITE_CLEAR = "clear"; const QString COMPOSITE_DISSOLVE = "dissolve"; @@ -74,7 +77,7 @@ const QString COMPOSITE_GAMMA_DARK = "gamma_dark"; const QString COMPOSITE_EXCLUSION = "exclusion"; const QString COMPOSITE_INVERTED_DIVIDE = "inverted_divide"; // XXX: not implemented anywhere yet const QString COMPOSITE_VIVID_LIGHT = "vivid_light"; -const QString COMPOSITE_LINEAR_LIGHT = "linear light"; // XXX: not implemented anywhere yet +const QString COMPOSITE_LINEAR_LIGHT = "linear light"; const QString COMPOSITE_PIN_LIGHT = "pin_light"; const QString COMPOSITE_HARD_MIX = "hard mix"; // XXX: not implemented anywhere yet const QString COMPOSITE_PASS_THROUGH = "pass through"; // XXX: not implemented anywhere yet diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index 25e5112..417df68 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -76,6 +76,18 @@ inline T clamp(typename KoColorSpaceMathsTraits::compositetype a) { return qBound(KoColorSpaceMathsTraits::zeroValue, a, KoColorSpaceMathsTraits::unitValue); } +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; +} + /* ------------------------ Auxiliary Functions --------------------------- / * definitions of auxiliary functions needed by the blending functions * or the KoCompositeOp* classes to calculate the pixel colors @@ -87,17 +99,121 @@ inline T unionShapeOpacy(T a, T b) { return T(composite_type(a) + b - mul(a,b)); } -template -inline T blend(T src, T srcAlpha, T dst, T dstAlpha) { - return mul(inv(srcAlpha), dstAlpha, dst) + mul(inv(dstAlpha), srcAlpha, src) + mul(dstAlpha, srcAlpha, blendFunc(src, dst)); +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 TReal getLuminosity(TReal r, TReal g, TReal b) { + return TReal(0.3)*r + TReal(0.59)*g + TReal(0.11)*b; +} + +template +inline void setLuminosity(TReal& r, TReal& g, TReal& b, TReal lum) { + + TReal d = lum - getLuminosity(r, g, b); + + r += d; + g += d; + b += d; + + TReal l = getLuminosity(r, g, b); + TReal n = min(r, g, b); + TReal x = max(r, g, b); + + if(n < TReal(0.0)) { + r = l + ((r-l) * l) / (l-n); + g = l + ((g-l) * l) / (l-n); + b = l + ((b-l) * l) / (l-n); + } + + if(x > TReal(1.0)) { + r = l + ((r-l) * (TReal(1.0)-l)) / (x-l); + g = l + ((g-l) * (TReal(1.0)-l)) / (x-l); + b = l + ((b-l) * (TReal(1.0)-l)) / (x-l); + } +} + +template +inline TReal getSaturation(TReal r, TReal g, TReal b) { + return max(r,g,b) - min(r,g,b); +} + +template +inline void setSaturation(TReal& r, TReal& g, TReal& b, TReal sat) { + TReal& min = r; + TReal& mid = g; + TReal& max = b; + + if(mid < min) { + TReal& tmp = min; + min = mid; + mid = tmp; + } + + if(max < mid) { + TReal& tmp = mid; + mid = max; + max = tmp; + } + + if(mid < min) { + TReal& tmp = min; + min = mid; + mid = tmp; + } + + if(max > min) { + mid = ((mid-min) * sat) / (max-min); + max = sat; + } else { + mid = TReal(0.0); + max = TReal(0.0); + } + + min = TReal(0.0); } /* ---------------- Blending/Compositing functions ------------------------ / * definitions of standard blending/compositing functions compatible - * to the ISO 32000-1 specification (for PDF filed) which also defines + * to the ISO 32000-1 specification (for PDF files) which also defines * the compositing functions who are also used in Adobe Photoshop (c) */ +template +inline void cfColor(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { + TReal lum = getLuminosity(dr, dg, db); + dr = sr; + dg = sg; + db = sb; + setLuminosity(dr, dg, db, lum); +} + +template +inline void cfLuminosity(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { + setLuminosity(dr, dg, db, getLuminosity(sr, sg, sb)); +} + +template +inline void cfSaturation(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { + TReal sat = getSaturation(sr, sg, sb); + TReal lum = getLuminosity(dr, dg, db); + setSaturation(dr, dg, db, sat); + setLuminosity(dr, dg, db, lum); +} + +template +inline void cfHue(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) { + TReal sat = getSaturation(dr, dg, db); + TReal lum = getLuminosity(dr, dg, db); + dr = sr; + dg = sg; + db = sb; + setSaturation(dr, dg, db, sat); + setLuminosity(dr, dg, db, lum); +} + template inline T cfColorBurn(T src, T dst) { if(src != KoColorSpaceMathsTraits::zeroValue) @@ -178,8 +294,10 @@ inline T cfVividLight(T src, T dst) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; if(src < KoColorSpaceMathsTraits::halfValue) { + if(src == KoColorSpaceMathsTraits::zeroValue) - return KoColorSpaceMathsTraits::zeroValue; //TODO: maybe better to return unitValue, must be verified + return (dst == KoColorSpaceMathsTraits::unitValue) ? + KoColorSpaceMathsTraits::unitValue : KoColorSpaceMathsTraits::zeroValue; // min(1,max(0,1-(1-dst) / (2*src))) composite_type src2 = composite_type(src) + src; @@ -188,7 +306,8 @@ inline T cfVividLight(T src, T dst) { } if(src == KoColorSpaceMathsTraits::unitValue) - return KoColorSpaceMathsTraits::unitValue; //TODO: maybe better to return zeroValue, must be verified + return (dst == KoColorSpaceMathsTraits::zeroValue) ? + KoColorSpaceMathsTraits::zeroValue : KoColorSpaceMathsTraits::unitValue; // min(1,max(0, dst / (2*(1-src))) composite_type srci2 = inv(src); @@ -199,7 +318,7 @@ inline T cfVividLight(T src, T dst) { template inline T cfPinLight(T src, T dst) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; - // TODO: verify that the formular is correct (the first max would be useless here) + // 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); @@ -219,6 +338,40 @@ inline T cfArcTangent(T src, T dst) { } template +inline T cfAllanon(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + // (dst + src) / 2 [or (dst + src) * 0.5] + return T((composite_type(src) + dst) * KoColorSpaceMathsTraits::halfValue / KoColorSpaceMathsTraits::unitValue); +} + +template +inline T cfLinearLight(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + // min(1,max(0,(dst + 2*src)-1)) + return clamp((composite_type(src) + src + dst) - KoColorSpaceMathsTraits::unitValue); +} + +template +inline T cfParallel(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + + // min(max(2 / (1/dst + 1/src), 0), 1) + composite_type unit = KoColorSpaceMathsTraits::unitValue; + composite_type s = (src != KoColorSpaceMathsTraits::zeroValue) ? div(unit, src) : unit; + composite_type d = (dst != KoColorSpaceMathsTraits::zeroValue) ? div(unit, dst) : unit; + + return clamp((unit+unit) * KoColorSpaceMathsTraits::unitValue / (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 < KoColorSpaceMathsTraits::zeroValue) ? T(-x) : T(x); +} + +template inline T cfGammaDark(T src, T dst) { if(src == KoColorSpaceMathsTraits::zeroValue) return KoColorSpaceMathsTraits::zeroValue; @@ -350,4 +503,51 @@ public: } }; + + + + +template +class KoCompositeOpGenericLum : public KoCompositeOpBase< Traits, KoCompositeOpGenericLum > +{ + typedef KoCompositeOpBase< Traits, KoCompositeOpGenericLum > base_class; + typedef typename Traits::channels_type channels_type; + + static const qint32 red_pos = Traits::red_pos; + static const qint32 green_pos = Traits::green_pos; + static const qint32 blue_pos = Traits::blue_pos; + +public: + KoCompositeOpGenericLum(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) + : base_class(cs, id, description, category, userVisible) { } + +public: + template + inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, + channels_type* dst, channels_type dstAlpha, + channels_type opacity, const QBitArray& channelFlags) { + Q_UNUSED(channelFlags); + + srcAlpha = mul(srcAlpha, opacity); + channels_type newDstAlpha = unionShapeOpacy(srcAlpha, dstAlpha); + + if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { + float srcR = scale(src[red_pos]); + float srcG = scale(src[green_pos]); + float srcB = scale(src[blue_pos]); + + float dstR = scale(dst[red_pos]); + float dstG = scale(dst[green_pos]); + float dstB = scale(dst[blue_pos]); + + compositeFunc(srcR, srcG, srcB, dstR, dstG, dstB); + dst[red_pos] = div(blend(src[red_pos] , srcAlpha, dst[red_pos] , dstAlpha, scale(dstR)), newDstAlpha); + dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], dstAlpha, scale(dstG)), newDstAlpha); + dst[blue_pos] = div(blend(src[blue_pos] , srcAlpha, dst[blue_pos] , dstAlpha, scale(dstB)), newDstAlpha); + } + + return newDstAlpha; + } +}; + #endif // KOCOMPOSITEOPFUNCTIONS_H_ diff --git a/libs/pigment/compositeops/KoCompositeOpGeneric.h b/libs/pigment/compositeops/KoCompositeOpGeneric.h index 92ca590..6a03e6b 100644 --- a/libs/pigment/compositeops/KoCompositeOpGeneric.h +++ b/libs/pigment/compositeops/KoCompositeOpGeneric.h @@ -53,7 +53,7 @@ public: if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { for(qint32 i=0; i (src[i], srcAlpha, dst[i], dstAlpha); + channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, compositeFunc(src[i],dst[i])); dst[i] = div(result, newDstAlpha); } } diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h index 000d2f8..d553128 100644 --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -21,14 +21,20 @@ #ifndef _KOCOMPOSITEOPS_H_ #define _KOCOMPOSITEOPS_H_ +#include + #include "KoColorSpace.h" +#include "KoColorSpaceTraits.h" -// #include "compositeops/KoCompositeOpAdd.h" +#include "compositeops/KoCompositeOpFunctions.h" +#include "compositeops/KoCompositeOpGeneric.h" #include "compositeops/KoCompositeOpAlphaDarken.h" +#include "compositeops/KoCompositeOpErase.h" +#include "compositeops/KoCompositeOpCopy2.h" +// #include "compositeops/KoCompositeOpAdd.h" // #include "compositeops/KoCompositeOpBurn.h" // #include "compositeops/KoCompositeOpDivide.h" // #include "compositeops/KoCompositeOpDodge.h" -#include "compositeops/KoCompositeOpErase.h" // #include "compositeops/KoCompositeOpMultiply.h" // #include "compositeops/KoCompositeOpOver.h" // #include "compositeops/KoCompositeOpOverlay.h" @@ -37,8 +43,91 @@ // #include "compositeops/KoCompositeOpInversedSubtract.h" // #include "compositeops/KoCompositeOpSoftlight.h" // #include "compositeops/KoCompositeOpHardlight.h" -#include "compositeops/KoCompositeOpCopy2.h" -#include "compositeops/KoCompositeOpGeneric.h" + + +namespace Private { + +template +struct AddGeneralOps +{ + static void add(KoColorSpace* cs) { Q_UNUSED(cs); } +}; + +template +struct AddGeneralOps +{ + typedef typename Traits::channels_type Arg; + + template + static void add(KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) { + cs->addCompositeOp(new KoCompositeOpGeneric(cs, id, description, category, userVisible)); + } + + static void add(KoColorSpace* cs) { + cs->addCompositeOp(new KoCompositeOpAlphaDarken(cs)); + cs->addCompositeOp(new KoCompositeOpCopy2(cs)); + cs->addCompositeOp(new KoCompositeOpErase(cs)); + + add<&cfOver>(cs, COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix()); + + add<&cfColorBurn> (cs, COMPOSITE_BURN , i18n("Color Burn") , KoCompositeOp::categoryLight()); + add<&cfColorDodge> (cs, COMPOSITE_DODGE , i18n("Color Dodge") , KoCompositeOp::categoryLight()); + add<&cfLinearBurn> (cs, COMPOSITE_LINEAR_BURN , i18n("Linear Burn") , KoCompositeOp::categoryLight()); + add<&cfAddition> (cs, COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), KoCompositeOp::categoryLight()); + add<&cfDarkenOnly> (cs, COMPOSITE_DARKEN , i18n("Darken") , KoCompositeOp::categoryLight()); + add<&cfLightenOnly>(cs, COMPOSITE_LIGHTEN , i18n("Lighten") , KoCompositeOp::categoryLight()); + add<&cfHardLight> (cs, COMPOSITE_HARD_LIGHT , i18n("Hard Light") , KoCompositeOp::categoryLight()); + add<&cfSoftLight> (cs, COMPOSITE_SOFT_LIGHT , i18n("Soft Light") , KoCompositeOp::categoryLight()); + add<&cfGammaLight> (cs, COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light") , KoCompositeOp::categoryLight()); + add<&cfGammaDark> (cs, COMPOSITE_GAMMA_DARK , i18n("Gamma Dark") , KoCompositeOp::categoryLight()); + add<&cfVividLight> (cs, COMPOSITE_VIVID_LIGHT , i18n("Vivid 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<&cfAddition> (cs, COMPOSITE_ADD , i18n("Addition") , KoCompositeOp::categoryArithmetic()); + add<&cfSubtract> (cs, COMPOSITE_SUBTRACT , i18n("Subtract") , KoCompositeOp::categoryArithmetic()); + add<&cfDifference>(cs, COMPOSITE_DIFF , i18n("Difference"), KoCompositeOp::categoryArithmetic()); + add<&cfMultiply> (cs, COMPOSITE_MULT , i18n("Multiply") , KoCompositeOp::categoryArithmetic()); + add<&cfDivide> (cs, COMPOSITE_DIVIDE , i18n("Divide") , KoCompositeOp::categoryArithmetic()); + add<&cfExclusion> (cs, COMPOSITE_EXCLUSION, i18n("Exclusion") , KoCompositeOp::categoryArithmetic()); + + add<&cfScreen> (cs, COMPOSITE_SCREEN , i18n("Screen") , KoCompositeOp::categoryColor()); + add<&cfOverlay>(cs, COMPOSITE_OVERLAY, i18n("Overlay"), KoCompositeOp::categoryColor()); + + add<&cfArcTangent> (cs, COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent") , KoCompositeOp::categoryMisc()); + add<&cfGeometricMean>(cs, COMPOSITE_GEOMETRIC_MEAN, i18n("Geometric Mean"), KoCompositeOp::categoryMisc()); + add<&cfAllanon> (cs, COMPOSITE_ALLANON , i18n("Allanon") , KoCompositeOp::categoryMisc()); + add<&cfParallel> (cs, COMPOSITE_PARALLEL , i18n("Parallel") , KoCompositeOp::categoryMisc()); + add<&cfEquivalence> (cs, COMPOSITE_EQUIVALENCE , i18n("Equivalence") , KoCompositeOp::categoryMisc()); + } +}; + +template +struct AddHSLOps +{ + static void add(KoColorSpace* cs) { Q_UNUSED(cs); } +}; + +template +struct AddHSLOps +{ + typedef float Arg; + + template + static void add(KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) { + cs->addCompositeOp(new KoCompositeOpGenericLum(cs, id, description, category, userVisible)); + } + + static void add(KoColorSpace* cs) { + add<&cfColor>(cs, COMPOSITE_COLOR, i18n("Color"), KoCompositeOp::categoryColor()); + add<&cfHue> (cs, COMPOSITE_HUE , i18n("Hue") , KoCompositeOp::categoryColor()); + + add<&cfLuminosity>(cs, COMPOSITE_LUMINIZE , i18n("Luminosity"), KoCompositeOp::categoryMix()); + add<&cfSaturation>(cs, COMPOSITE_SATURATION, i18n("Saturation"), KoCompositeOp::categoryMix()); + } +}; + +} /** * This function add to the colorspace all the composite ops defined by @@ -47,13 +136,16 @@ template void addStandardCompositeOps(KoColorSpace* cs) { + //cs->addCompositeOp(new KoCompositeOpAlphaDarken<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpCopy2<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpErase<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpAdd<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpAlphaDarken<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpAlphaDarken<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpBurn<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpCopy2<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpCopy2<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpDivide<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpDodge<_Traits_>(cs)); - cs->addCompositeOp(new KoCompositeOpErase<_Traits_>(cs)); + //cs->addCompositeOp(new KoCompositeOpErase<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpMultiply<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpOver<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpOverlay<_Traits_>(cs)); @@ -62,32 +154,13 @@ void addStandardCompositeOps(KoColorSpace* cs) //cs->addCompositeOp(new KoCompositeOpSoftlight<_Traits_>(cs)); //cs->addCompositeOp(new KoCompositeOpHardlight<_Traits_>(cs)); - typedef typename _Traits_::channels_type T; - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOver >(cs, COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix())); + typedef typename _Traits_::channels_type channels_type; - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorBurn >(cs, COMPOSITE_BURN , i18n("Color Burn"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorDodge >(cs, COMPOSITE_DODGE , i18n("Color Dodge"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLinearBurn >(cs, COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDarkenOnly >(cs, COMPOSITE_DARKEN , i18n("Darken"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLightenOnly >(cs, COMPOSITE_LIGHTEN , i18n("Lighten"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfHardLight >(cs, COMPOSITE_HARD_LIGHT , i18n("Hard Light"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSoftLight >(cs, COMPOSITE_SOFT_LIGHT , i18n("Soft Light"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGammaLight >(cs, COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGammaDark >(cs, COMPOSITE_GAMMA_DARK , i18n("Gamma Dark"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfVividLight >(cs, COMPOSITE_VIVID_LIGHT , i18n("Vivid Light"), KoCompositeOp::categoryLight())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfPinLight >(cs, COMPOSITE_PIN_LIGHT , i18n("Pin Light"), KoCompositeOp::categoryLight())); + static const bool useGeneralOps = true; + static const bool useHSLOps = boost::is_base_of, _Traits_>::value; - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen >(cs, COMPOSITE_SCREEN , i18n("Screen"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOverlay >(cs, COMPOSITE_OVERLAY , i18n("Overlay"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition >(cs, COMPOSITE_ADD , i18n("Addition"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract >(cs, COMPOSITE_SUBTRACT , i18n("Subtract"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference >(cs, COMPOSITE_DIFF , i18n("Difference"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply >(cs, COMPOSITE_MULT , i18n("Multiply"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide >(cs, COMPOSITE_DIVIDE , i18n("Divide"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion >(cs, COMPOSITE_EXCLUSION , i18n("Exclusion"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfArcTangent >(cs, COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent"), KoCompositeOp::categoryArithmetic())); - cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGeometricMean >(cs, COMPOSITE_GEOMETRIC_MEAN, i18n("Geometric Mean"), KoCompositeOp::categoryArithmetic())); + Private::AddGeneralOps<_Traits_, useGeneralOps>::add(cs); + Private::AddHSLOps <_Traits_, useHSLOps >::add(cs); } #endif -- 1.7.1 From b8eb78751bd04f3d31680a080519c4329dcb509a Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Sun, 9 Jan 2011 18:02:36 +0100 Subject: [PATCH 10/15] Commented out the usage of the native CompositeOps in the RgbU16 and RGbU8 color spaces. This was done to be able to use the CompositeOps in the pigment library. --- .../lcms/colorspaces/rgb_u16/RgbU16ColorSpace.cpp | 12 ++++++------ .../lcms/colorspaces/rgb_u8/RgbU8ColorSpace.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/colorengines/lcms/colorspaces/rgb_u16/RgbU16ColorSpace.cpp b/plugins/colorengines/lcms/colorspaces/rgb_u16/RgbU16ColorSpace.cpp index 785430e..bb70705 100644 --- a/plugins/colorengines/lcms/colorspaces/rgb_u16/RgbU16ColorSpace.cpp +++ b/plugins/colorengines/lcms/colorspaces/rgb_u16/RgbU16ColorSpace.cpp @@ -39,15 +39,15 @@ RgbU16ColorSpace::RgbU16ColorSpace(KoColorProfile *p) : addStandardCompositeOps(this); - addCompositeOp(new RgbCompositeOpDarken(this)); - addCompositeOp(new RgbCompositeOpLighten(this)); - addCompositeOp(new RgbCompositeOpHue(this)); - addCompositeOp(new RgbCompositeOpSaturation(this)); +// addCompositeOp(new RgbCompositeOpDarken(this)); +// addCompositeOp(new RgbCompositeOpLighten(this)); +// addCompositeOp(new RgbCompositeOpHue(this)); +// addCompositeOp(new RgbCompositeOpSaturation(this)); addCompositeOp(new RgbCompositeOpValue(this)); - addCompositeOp(new RgbCompositeOpColor(this)); +// addCompositeOp(new RgbCompositeOpColor(this)); addCompositeOp(new RgbCompositeOpIn(this)); addCompositeOp(new RgbCompositeOpOut(this)); - addCompositeOp(new RgbCompositeOpDiff(this)); +// addCompositeOp(new RgbCompositeOpDiff(this)); addCompositeOp(new RgbCompositeOpBumpmap(this)); // addCompositeOp(new RgbCompositeOpClear(this)); addCompositeOp(new RgbCompositeOpDissolve(this)); diff --git a/plugins/colorengines/lcms/colorspaces/rgb_u8/RgbU8ColorSpace.cpp b/plugins/colorengines/lcms/colorspaces/rgb_u8/RgbU8ColorSpace.cpp index 13facca..b87c8a0 100644 --- a/plugins/colorengines/lcms/colorspaces/rgb_u8/RgbU8ColorSpace.cpp +++ b/plugins/colorengines/lcms/colorspaces/rgb_u8/RgbU8ColorSpace.cpp @@ -75,15 +75,15 @@ RgbU8ColorSpace::RgbU8ColorSpace(KoColorProfile *p) : // ADD, ALPHA_DARKEN, BURN, DIVIDE, DODGE, ERASE, MULTIPLY, OVER, OVERLAY, SCREEN, SUBTRACT addStandardCompositeOps(this); - addCompositeOp(new RgbCompositeOpDarken(this)); - addCompositeOp(new RgbCompositeOpLighten(this)); - addCompositeOp(new RgbCompositeOpHue(this)); - addCompositeOp(new RgbCompositeOpSaturation(this)); +// addCompositeOp(new RgbCompositeOpDarken(this)); +// addCompositeOp(new RgbCompositeOpLighten(this)); +// addCompositeOp(new RgbCompositeOpHue(this)); +// addCompositeOp(new RgbCompositeOpSaturation(this)); addCompositeOp(new RgbCompositeOpValue(this)); - addCompositeOp(new RgbCompositeOpColor(this)); +// addCompositeOp(new RgbCompositeOpColor(this)); addCompositeOp(new RgbCompositeOpIn(this)); addCompositeOp(new RgbCompositeOpOut(this)); - addCompositeOp(new RgbCompositeOpDiff(this)); +// addCompositeOp(new RgbCompositeOpDiff(this)); addCompositeOp(new RgbCompositeOpBumpmap(this)); // addCompositeOp(new RgbCompositeOpClear(this)); addCompositeOp(new RgbCompositeOpDissolve(this)); -- 1.7.1 From 37204ed91a366b5ba985a274bbfff0f62d1891a9 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Sun, 9 Jan 2011 19:05:08 +0100 Subject: [PATCH 11/15] Done a bit of cleanup and renaming. And The KoCompositeOpBase template class now has an own header file. --- libs/pigment/compositeops/KoCompositeOpBase.h | 122 ++++++++++++++++ libs/pigment/compositeops/KoCompositeOpFunctions.h | 151 +------------------- libs/pigment/compositeops/KoCompositeOpGeneric.h | 69 ++++++++- libs/pigment/compositeops/KoCompositeOps.h | 5 +- 4 files changed, 190 insertions(+), 157 deletions(-) create mode 100644 libs/pigment/compositeops/KoCompositeOpBase.h diff --git a/libs/pigment/compositeops/KoCompositeOpBase.h b/libs/pigment/compositeops/KoCompositeOpBase.h new file mode 100644 index 0000000..eaa672b --- /dev/null +++ b/libs/pigment/compositeops/KoCompositeOpBase.h @@ -0,0 +1,122 @@ +/* + * 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 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 KOCOMPOSITEO_BASE_H_ +#define KOCOMPOSITEO_BASE_H_ + +#include +#include "KoCompositeOpFunctions.h" + +/** + * A template base class that can be used for most composite modes/ops + * + * @param _compositeOp this template parameter is a class that must be + * derived fom KoCompositeOpBase and must define the static member function + * template + * inline static channels_type composeColorChannels( + * const channels_type* src, + * channels_type srcAlpha, + * channels_type* dst, + * channels_type dstAlpha, + * channels_type opacity, + * const QBitArray& channelFlags + * ) + * + * where channels_type is _CSTraits::channels_type + */ +template +class KoCompositeOpBase : public KoCompositeOp +{ + typedef typename _CSTraits::channels_type channels_type; + static const qint32 channels_nb = _CSTraits::channels_nb; + static const qint32 alpha_pos = _CSTraits::alpha_pos; + +public: + + KoCompositeOpBase(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible) + : KoCompositeOp(cs, id, description, category, userVisible) { } + +private: + template + void genericComposite(quint8* dstRowStart , qint32 dstRowStride , + const quint8* srcRowStart , qint32 srcRowStride , + const quint8* maskRowStart, qint32 maskRowStride, + qint32 rows, qint32 cols, quint8 U8_opacity, const QBitArray& channelFlags) const { + + qint32 srcInc = (srcRowStride == 0) ? 0 : channels_nb; + bool useMask = maskRowStart != 0; + channels_type unitValue = KoColorSpaceMathsTraits::unitValue; + channels_type opacity = KoColorSpaceMaths::scaleToA(U8_opacity); + + for(; rows>0; --rows) { + const channels_type* src = reinterpret_cast(srcRowStart); + channels_type* dst = reinterpret_cast(dstRowStart); + const quint8* mask = maskRowStart; + + for(qint32 c=cols; c>0; --c) { + channels_type srcAlpha = (alpha_pos == -1) ? unitValue : src[alpha_pos]; + channels_type dstAlpha = (alpha_pos == -1) ? unitValue : dst[alpha_pos]; + channels_type blend = useMask ? mul(opacity, scale(*mask)) : opacity; + + channels_type newDstAlpha = _compositeOp::template composeColorChannels( + src, srcAlpha, dst, dstAlpha, blend, channelFlags + ); + + if(alpha_pos != -1) + dst[alpha_pos] = alphaLocked ? dstAlpha : newDstAlpha; + + src += srcInc; + dst += channels_nb; + ++mask; + } + + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + maskRowStart += maskRowStride; + } + } + +public: + using KoCompositeOp::composite; + + virtual void composite(quint8* dstRowStart , qint32 dstRowStride , + const quint8* srcRowStart , qint32 srcRowStride , + const quint8* maskRowStart, qint32 maskRowStride, + qint32 rows, qint32 cols, quint8 U8_opacity, const QBitArray& channelFlags) const { + + const QBitArray& flags = channelFlags.isEmpty() ? QBitArray(channels_nb,true) : channelFlags; + bool allChannelFlags = channelFlags.isEmpty(); + bool alphaLocked = (alpha_pos != -1) && !flags.testBit(alpha_pos); + + if(alphaLocked) { + if(allChannelFlags) + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + else + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + } + else { + if(allChannelFlags) + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + else + genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); + } + } +}; + +#endif // KOCOMPOSITEO_BASE_H_ diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index 417df68..7f1fa7a 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -17,12 +17,10 @@ * Boston, MA 02110-1301, USA. */ -#ifndef KOCOMPOSITEOPFUNCTIONS_H_ -#define KOCOMPOSITEOPFUNCTIONS_H_ +#ifndef KOCOMPOSITEOP_FUNCTIONS_H_ +#define KOCOMPOSITEOP_FUNCTIONS_H_ #include -#include -#include /* --------------------- Arithmetic functions ----------------------------- / * definitions of standard arithmetic functions. all computations are meant @@ -407,147 +405,4 @@ inline T cfDarkenOnly(T src, T dst) { return qMin(src, dst); } template inline T cfLightenOnly(T src, T dst) { return qMax(src, dst); } -/** - * A template base class that can be used for most composite modes/ops - * - * @param _compositeOp this template parameter is a class that must be - * derived fom KoCompositeOpBase and must define the static member function - * template - * inline static channels_type composeColorChannels( - * const channels_type* src, - * channels_type srcAlpha, - * channels_type* dst, - * channels_type dstAlpha, - * channels_type opacity, - * const QBitArray& channelFlags - * ) - * - * where channels_type is _CSTraits::channels_type - */ -template -class KoCompositeOpBase : public KoCompositeOp -{ - typedef typename _CSTraits::channels_type channels_type; - static const qint32 channels_nb = _CSTraits::channels_nb; - static const qint32 alpha_pos = _CSTraits::alpha_pos; - -public: - - KoCompositeOpBase(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible) - : KoCompositeOp(cs, id, description, category, userVisible) { } - -private: - template - void genericComposite(quint8* dstRowStart , qint32 dstRowStride , - const quint8* srcRowStart , qint32 srcRowStride , - const quint8* maskRowStart, qint32 maskRowStride, - qint32 rows, qint32 cols, quint8 U8_opacity, const QBitArray& channelFlags) const { - - qint32 srcInc = (srcRowStride == 0) ? 0 : channels_nb; - bool useMask = maskRowStart != 0; - channels_type unitValue = KoColorSpaceMathsTraits::unitValue; - channels_type opacity = KoColorSpaceMaths::scaleToA(U8_opacity); - - for(; rows>0; --rows) { - const channels_type* src = reinterpret_cast(srcRowStart); - channels_type* dst = reinterpret_cast(dstRowStart); - const quint8* mask = maskRowStart; - - for(qint32 c=cols; c>0; --c) { - channels_type srcAlpha = (alpha_pos == -1) ? unitValue : src[alpha_pos]; - channels_type dstAlpha = (alpha_pos == -1) ? unitValue : dst[alpha_pos]; - channels_type blend = useMask ? mul(opacity, scale(*mask)) : opacity; - - channels_type newDstAlpha = _compositeOp::template composeColorChannels( - src, srcAlpha, dst, dstAlpha, blend, channelFlags - ); - - if(alpha_pos != -1) - dst[alpha_pos] = alphaLocked ? dstAlpha : newDstAlpha; - - src += srcInc; - dst += channels_nb; - ++mask; - } - - srcRowStart += srcRowStride; - dstRowStart += dstRowStride; - maskRowStart += maskRowStride; - } - } - -public: - using KoCompositeOp::composite; - - virtual void composite(quint8* dstRowStart , qint32 dstRowStride , - const quint8* srcRowStart , qint32 srcRowStride , - const quint8* maskRowStart, qint32 maskRowStride, - qint32 rows, qint32 cols, quint8 U8_opacity, const QBitArray& channelFlags) const { - - const QBitArray& flags = channelFlags.isEmpty() ? QBitArray(channels_nb,true) : channelFlags; - bool allChannelFlags = channelFlags.isEmpty(); - bool alphaLocked = (alpha_pos != -1) && !flags.testBit(alpha_pos); - - if(alphaLocked) { - if(allChannelFlags) - genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); - else - genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); - } - else { - if(allChannelFlags) - genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); - else - genericComposite(dstRowStart, dstRowStride, srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); - } - } -}; - - - - - -template -class KoCompositeOpGenericLum : public KoCompositeOpBase< Traits, KoCompositeOpGenericLum > -{ - typedef KoCompositeOpBase< Traits, KoCompositeOpGenericLum > base_class; - typedef typename Traits::channels_type channels_type; - - static const qint32 red_pos = Traits::red_pos; - static const qint32 green_pos = Traits::green_pos; - static const qint32 blue_pos = Traits::blue_pos; - -public: - KoCompositeOpGenericLum(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) - : base_class(cs, id, description, category, userVisible) { } - -public: - template - inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, - channels_type* dst, channels_type dstAlpha, - channels_type opacity, const QBitArray& channelFlags) { - Q_UNUSED(channelFlags); - - srcAlpha = mul(srcAlpha, opacity); - channels_type newDstAlpha = unionShapeOpacy(srcAlpha, dstAlpha); - - if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { - float srcR = scale(src[red_pos]); - float srcG = scale(src[green_pos]); - float srcB = scale(src[blue_pos]); - - float dstR = scale(dst[red_pos]); - float dstG = scale(dst[green_pos]); - float dstB = scale(dst[blue_pos]); - - compositeFunc(srcR, srcG, srcB, dstR, dstG, dstB); - dst[red_pos] = div(blend(src[red_pos] , srcAlpha, dst[red_pos] , dstAlpha, scale(dstR)), newDstAlpha); - dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], dstAlpha, scale(dstG)), newDstAlpha); - dst[blue_pos] = div(blend(src[blue_pos] , srcAlpha, dst[blue_pos] , dstAlpha, scale(dstB)), newDstAlpha); - } - - return newDstAlpha; - } -}; - -#endif // KOCOMPOSITEOPFUNCTIONS_H_ +#endif // KOCOMPOSITEOP_FUNCTIONS_H_ diff --git a/libs/pigment/compositeops/KoCompositeOpGeneric.h b/libs/pigment/compositeops/KoCompositeOpGeneric.h index 6a03e6b..308cc0a 100644 --- a/libs/pigment/compositeops/KoCompositeOpGeneric.h +++ b/libs/pigment/compositeops/KoCompositeOpGeneric.h @@ -21,25 +21,30 @@ #define _KOCOMPOSITEO_GENERIC_H_ #include "KoCompositeOpFunctions.h" +#include "KoCompositeOpBase.h" /** - * A template version of the burn composite operation to use in colorspaces. + * Generic CompositeOp for separable channel compositing functions + * + * A template to generate a KoCompositeOp class by just specifying a + * blending/compositing function. This template works with compositing functions + * for separable channels (means each channel of a pixel can be processed separately) */ template< class Traits, typename Traits::channels_type compositeFunc(typename Traits::channels_type, typename Traits::channels_type) > -class KoCompositeOpGeneric : public KoCompositeOpBase< Traits, KoCompositeOpGeneric > +class KoCompositeOpGenericSC: public KoCompositeOpBase< Traits, KoCompositeOpGenericSC > { - typedef KoCompositeOpBase< Traits, KoCompositeOpGeneric > base_class; - typedef typename Traits::channels_type channels_type; - typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + typedef KoCompositeOpBase< Traits, KoCompositeOpGenericSC > base_class; + typedef typename Traits::channels_type channels_type; + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; static const qint32 channels_nb = Traits::channels_nb; static const qint32 alpha_pos = Traits::alpha_pos; public: - KoCompositeOpGeneric(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) + KoCompositeOpGenericSC(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) : base_class(cs, id, description, category, userVisible) { } public: @@ -63,4 +68,56 @@ public: } }; + +/** + * Generic CompositeOp for nonseparable/HSL channel compositing functions + * + * A template to generate a KoCompositeOp class by just specifying a + * blending/compositing function. This template works with compositing functions + * for RGB channels only (the channels can not be processed separately) + */ +template +class KoCompositeOpGenericHSL: public KoCompositeOpBase< Traits, KoCompositeOpGenericHSL > +{ + typedef KoCompositeOpBase< Traits, KoCompositeOpGenericHSL > base_class; + typedef typename Traits::channels_type channels_type; + + static const qint32 red_pos = Traits::red_pos; + static const qint32 green_pos = Traits::green_pos; + static const qint32 blue_pos = Traits::blue_pos; + +public: + KoCompositeOpGenericHSL(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) + : base_class(cs, id, description, category, userVisible) { } + +public: + template + inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, + channels_type* dst, channels_type dstAlpha, + channels_type opacity, const QBitArray& channelFlags) { + Q_UNUSED(channelFlags); + + srcAlpha = mul(srcAlpha, opacity); + channels_type newDstAlpha = unionShapeOpacy(srcAlpha, dstAlpha); + + if(newDstAlpha != KoColorSpaceMathsTraits::zeroValue) { + float srcR = scale(src[red_pos]); + float srcG = scale(src[green_pos]); + float srcB = scale(src[blue_pos]); + + float dstR = scale(dst[red_pos]); + float dstG = scale(dst[green_pos]); + float dstB = scale(dst[blue_pos]); + + compositeFunc(srcR, srcG, srcB, dstR, dstG, dstB); + + dst[red_pos] = div(blend(src[red_pos] , srcAlpha, dst[red_pos] , dstAlpha, scale(dstR)), newDstAlpha); + dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], dstAlpha, scale(dstG)), newDstAlpha); + dst[blue_pos] = div(blend(src[blue_pos] , srcAlpha, dst[blue_pos] , dstAlpha, scale(dstB)), newDstAlpha); + } + + return newDstAlpha; + } +}; + #endif // _KOCOMPOSITEO_GENERIC_H_ diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h index d553128..d00f2d1 100644 --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -26,7 +26,6 @@ #include "KoColorSpace.h" #include "KoColorSpaceTraits.h" -#include "compositeops/KoCompositeOpFunctions.h" #include "compositeops/KoCompositeOpGeneric.h" #include "compositeops/KoCompositeOpAlphaDarken.h" #include "compositeops/KoCompositeOpErase.h" @@ -60,7 +59,7 @@ struct AddGeneralOps template static void add(KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) { - cs->addCompositeOp(new KoCompositeOpGeneric(cs, id, description, category, userVisible)); + cs->addCompositeOp(new KoCompositeOpGenericSC(cs, id, description, category, userVisible)); } static void add(KoColorSpace* cs) { @@ -115,7 +114,7 @@ struct AddHSLOps template static void add(KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) { - cs->addCompositeOp(new KoCompositeOpGenericLum(cs, id, description, category, userVisible)); + cs->addCompositeOp(new KoCompositeOpGenericHSL(cs, id, description, category, userVisible)); } static void add(KoColorSpace* cs) { -- 1.7.1 From 9eb77baa7d75aa38f92bb52b6aa88ae6aa0768bb Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Mon, 10 Jan 2011 00:14:01 +0100 Subject: [PATCH 12/15] Added composite modes "Grain Merge", "Grain Extract", "Hard Mix" and "Copy Red/Green/Blue/Opacy". --- libs/pigment/KoCompositeOp.h | 2 + .../compositeops/KoCompositeOpCopyChannel.h | 59 ++++++++++++++++++++ libs/pigment/compositeops/KoCompositeOpFunctions.h | 20 +++++++ libs/pigment/compositeops/KoCompositeOps.h | 24 +++++++- 4 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 libs/pigment/compositeops/KoCompositeOpCopyChannel.h diff --git a/libs/pigment/KoCompositeOp.h b/libs/pigment/KoCompositeOp.h index 920fe3e..aa32c4e 100644 --- a/libs/pigment/KoCompositeOp.h +++ b/libs/pigment/KoCompositeOp.h @@ -55,6 +55,8 @@ const QString COMPOSITE_BUMPMAP = "bumpmap"; const QString COMPOSITE_CLEAR = "clear"; const QString COMPOSITE_DISSOLVE = "dissolve"; const QString COMPOSITE_DISPLACE = "displace"; +const QString COMPOSITE_GRAIN_MERGE = "grain_merge"; +const QString COMPOSITE_GRAIN_EXTRACT = "grain_extract"; const QString COMPOSITE_NO = "nocomposition"; const QString COMPOSITE_DARKEN = "darken"; const QString COMPOSITE_LIGHTEN = "lighten"; diff --git a/libs/pigment/compositeops/KoCompositeOpCopyChannel.h b/libs/pigment/compositeops/KoCompositeOpCopyChannel.h new file mode 100644 index 0000000..7bb6b40 --- /dev/null +++ b/libs/pigment/compositeops/KoCompositeOpCopyChannel.h @@ -0,0 +1,59 @@ +/* + * 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 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 _KOCOMPOSITEO_COPY_CHANNEL_H_ +#define _KOCOMPOSITEO_COPY_CHANNEL_H_ + +#include "KoCompositeOpBase.h" + +/** + * KoCompositeOpCopyChannel class + * + * This class creates a CompositeOp that will just copy/blend + * a source channel to a destination channel + * + * @param channel_pos the channel to copy/blend + */ +template +class KoCompositeOpCopyChannel: public KoCompositeOpBase< Traits, KoCompositeOpCopyChannel > +{ + typedef KoCompositeOpBase< Traits, KoCompositeOpCopyChannel > base_class; + typedef typename Traits::channels_type channels_type; + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + + static const qint32 alpha_pos = Traits::alpha_pos; + +public: + KoCompositeOpCopyChannel(const KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) + : base_class(cs, id, description, category, userVisible) { } + +public: + template + inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, + channels_type* dst, channels_type dstAlpha, + channels_type opacity, const QBitArray& channelFlags) { + if(channel_pos == alpha_pos) + return lerp(dstAlpha, srcAlpha, opacity); + + dst[channel_pos] = lerp(dst[channel_pos], src[channel_pos], opacity); + return dstAlpha; + } +}; + +#endif // _KOCOMPOSITEO_COPY_CHANNEL_H_ diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index 7f1fa7a..a6ec380 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -370,6 +370,26 @@ inline T cfEquivalence(T src, T dst) { } template +inline T cfGrainMerge(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + return clamp(composite_type(dst) + src - KoColorSpaceMathsTraits::halfValue); +} + +template +inline T cfGrainExtract(T src, T dst) { + typedef typename KoColorSpaceMathsTraits::compositetype composite_type; + return clamp(composite_type(dst) - src + KoColorSpaceMathsTraits::halfValue); +} + +template +inline T cfHardMix(T src, T dst) { + if(dst > KoColorSpaceMathsTraits::halfValue) + return cfColorDodge(src, dst); + + return cfColorBurn(src, dst); +} + +template inline T cfGammaDark(T src, T dst) { if(src == KoColorSpaceMathsTraits::zeroValue) return KoColorSpaceMathsTraits::zeroValue; diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h index d00f2d1..e514e35 100644 --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -27,6 +27,7 @@ #include "KoColorSpaceTraits.h" #include "compositeops/KoCompositeOpGeneric.h" +#include "compositeops/KoCompositeOpCopyChannel.h" #include "compositeops/KoCompositeOpAlphaDarken.h" #include "compositeops/KoCompositeOpErase.h" #include "compositeops/KoCompositeOpCopy2.h" @@ -63,11 +64,14 @@ struct AddGeneralOps } static void add(KoColorSpace* cs) { + cs->addCompositeOp(new KoCompositeOpOver(cs)); cs->addCompositeOp(new KoCompositeOpAlphaDarken(cs)); cs->addCompositeOp(new KoCompositeOpCopy2(cs)); cs->addCompositeOp(new KoCompositeOpErase(cs)); - add<&cfOver>(cs, COMPOSITE_OVER, i18n("Normal"), 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<&cfColorBurn> (cs, COMPOSITE_BURN , i18n("Color Burn") , KoCompositeOp::categoryLight()); add<&cfColorDodge> (cs, COMPOSITE_DODGE , i18n("Color Dodge") , KoCompositeOp::categoryLight()); @@ -102,22 +106,34 @@ struct AddGeneralOps }; template -struct AddHSLOps +struct AddRGBOps { static void add(KoColorSpace* cs) { Q_UNUSED(cs); } }; template -struct AddHSLOps +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; + static const qint32 alpha_pos = Traits::alpha_pos; + template static void add(KoColorSpace* cs, const QString& id, const QString& description, const QString& category, bool userVisible=true) { cs->addCompositeOp(new KoCompositeOpGenericHSL(cs, id, description, category, userVisible)); } 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())); + + if(alpha_pos != -1) + cs->addCompositeOp(new KoCompositeOpCopyChannel(cs, COMPOSITE_COPY_OPACITY, i18n("Copy Alpha") , KoCompositeOp::categoryMisc())); + add<&cfColor>(cs, COMPOSITE_COLOR, i18n("Color"), KoCompositeOp::categoryColor()); add<&cfHue> (cs, COMPOSITE_HUE , i18n("Hue") , KoCompositeOp::categoryColor()); @@ -159,7 +175,7 @@ void addStandardCompositeOps(KoColorSpace* cs) static const bool useHSLOps = boost::is_base_of, _Traits_>::value; Private::AddGeneralOps<_Traits_, useGeneralOps>::add(cs); - Private::AddHSLOps <_Traits_, useHSLOps >::add(cs); + Private::AddRGBOps <_Traits_, useHSLOps >::add(cs); } #endif -- 1.7.1 From e273dfe496530851e629384f9c1e6a8f20340628 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Mon, 10 Jan 2011 00:39:47 +0100 Subject: [PATCH 13/15] Added channel flags test for KoCompositeOpCopyChannel class and changed Color Dodge and Burn. The dodge and burn algorithms where changed to fit the definition in ISO 32000 part 2. --- .../compositeops/KoCompositeOpCopyChannel.h | 9 +++++-- libs/pigment/compositeops/KoCompositeOpFunctions.h | 24 +++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/libs/pigment/compositeops/KoCompositeOpCopyChannel.h b/libs/pigment/compositeops/KoCompositeOpCopyChannel.h index 7bb6b40..1747334 100644 --- a/libs/pigment/compositeops/KoCompositeOpCopyChannel.h +++ b/libs/pigment/compositeops/KoCompositeOpCopyChannel.h @@ -48,10 +48,13 @@ public: inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha, channels_type* dst, channels_type dstAlpha, channels_type opacity, const QBitArray& channelFlags) { - if(channel_pos == alpha_pos) - return lerp(dstAlpha, srcAlpha, opacity); + if(allChannelFlags || channelFlags.testBit(channel_pos)) { + if(channel_pos == alpha_pos) + return lerp(dstAlpha, srcAlpha, opacity); + + dst[channel_pos] = lerp(dst[channel_pos], src[channel_pos], opacity); + } - dst[channel_pos] = lerp(dst[channel_pos], src[channel_pos], opacity); return dstAlpha; } }; diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index a6ec380..9b75faf 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -214,9 +214,15 @@ inline void cfHue(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& db) template inline T cfColorBurn(T src, T dst) { - if(src != KoColorSpaceMathsTraits::zeroValue) - return inv(clamp(div(inv(dst), src))); - return KoColorSpaceMathsTraits::zeroValue; + if(dst == KoColorSpaceMathsTraits::unitValue) + return KoColorSpaceMathsTraits::unitValue; + + T invDst = inv(dst); + + if(src < invDst) + return KoColorSpaceMathsTraits::zeroValue; + + return inv(clamp(div(invDst, src))); } template @@ -227,9 +233,15 @@ inline T cfLinearBurn(T src, T dst) { template inline T cfColorDodge(T src, T dst) { - if(src != KoColorSpaceMathsTraits::unitValue) - return clamp(div(dst, inv(src))); - return KoColorSpaceMathsTraits::unitValue; + if(dst == KoColorSpaceMathsTraits::zeroValue) + return KoColorSpaceMathsTraits::zeroValue; + + T invSrc = inv(src); + + if(invSrc < dst) + return KoColorSpaceMathsTraits::unitValue; + + return clamp(div(dst, invSrc)); } template -- 1.7.1 From 658c78659c9f17c37d12c8f99ad3d1fbcdbe4df9 Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Mon, 10 Jan 2011 23:02:59 +0100 Subject: [PATCH 14/15] Added "Additive-Substractive" composition function and imporved "Divide" composition. Also made the KoCompositeOpGenericHSL class aware of channel flags. --- libs/pigment/KoCompositeOp.h | 3 ++- .../compositeops/KoCompositeOpCopyChannel.h | 3 ++- libs/pigment/compositeops/KoCompositeOpFunctions.h | 11 ++++++++++- libs/pigment/compositeops/KoCompositeOpGeneric.h | 11 ++++++++--- libs/pigment/compositeops/KoCompositeOps.h | 11 ++++++----- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/libs/pigment/KoCompositeOp.h b/libs/pigment/KoCompositeOp.h index aa32c4e..d0fb207 100644 --- a/libs/pigment/KoCompositeOp.h +++ b/libs/pigment/KoCompositeOp.h @@ -45,6 +45,7 @@ const QString COMPOSITE_DIVIDE = "divide"; const QString COMPOSITE_ARC_TANGENT = "arc_tangent"; const QString COMPOSITE_EQUIVALENCE = "equivalence"; const QString COMPOSITE_GEOMETRIC_MEAN = "geometric_mean"; +const QString COMPOSITE_ADDITIVE_SUBSTRACTIVE = "additive_substractive"; const QString COMPOSITE_DODGE = "dodge"; const QString COMPOSITE_LINEAR_DODGE = "linear_dodge"; const QString COMPOSITE_BURN = "burn"; @@ -81,7 +82,7 @@ const QString COMPOSITE_INVERTED_DIVIDE = "inverted_divide"; // XXX: not impleme const QString COMPOSITE_VIVID_LIGHT = "vivid_light"; const QString COMPOSITE_LINEAR_LIGHT = "linear light"; const QString COMPOSITE_PIN_LIGHT = "pin_light"; -const QString COMPOSITE_HARD_MIX = "hard mix"; // XXX: not implemented anywhere yet +const QString COMPOSITE_HARD_MIX = "hard mix"; const QString COMPOSITE_PASS_THROUGH = "pass through"; // XXX: not implemented anywhere yet const QString COMPOSITE_UNDEF = "underfined"; diff --git a/libs/pigment/compositeops/KoCompositeOpCopyChannel.h b/libs/pigment/compositeops/KoCompositeOpCopyChannel.h index 1747334..c17dc52 100644 --- a/libs/pigment/compositeops/KoCompositeOpCopyChannel.h +++ b/libs/pigment/compositeops/KoCompositeOpCopyChannel.h @@ -52,7 +52,8 @@ public: if(channel_pos == alpha_pos) return lerp(dstAlpha, srcAlpha, opacity); - dst[channel_pos] = lerp(dst[channel_pos], src[channel_pos], opacity); + srcAlpha = mul(srcAlpha, opacity); + dst[channel_pos] = lerp(dst[channel_pos], src[channel_pos], srcAlpha); } return dstAlpha; diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index 9b75faf..c70d27e 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -267,7 +267,9 @@ template inline T cfDivide(T src, T dst) { typedef typename KoColorSpaceMathsTraits::compositetype composite_type; if(src == KoColorSpaceMathsTraits::zeroValue) - return dst; + return (dst == KoColorSpaceMathsTraits::zeroValue) ? + KoColorSpaceMathsTraits::zeroValue : KoColorSpaceMathsTraits::unitValue; + return clamp(div(dst, src)); } @@ -402,6 +404,13 @@ inline T cfHardMix(T src, T dst) { } template +inline T cfAdditiveSubstractive(T src, T dst) { + // 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) { if(src == KoColorSpaceMathsTraits::zeroValue) return KoColorSpaceMathsTraits::zeroValue; diff --git a/libs/pigment/compositeops/KoCompositeOpGeneric.h b/libs/pigment/compositeops/KoCompositeOpGeneric.h index 308cc0a..a400b95 100644 --- a/libs/pigment/compositeops/KoCompositeOpGeneric.h +++ b/libs/pigment/compositeops/KoCompositeOpGeneric.h @@ -111,9 +111,14 @@ public: compositeFunc(srcR, srcG, srcB, dstR, dstG, dstB); - dst[red_pos] = div(blend(src[red_pos] , srcAlpha, dst[red_pos] , dstAlpha, scale(dstR)), newDstAlpha); - dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], dstAlpha, scale(dstG)), newDstAlpha); - dst[blue_pos] = div(blend(src[blue_pos] , srcAlpha, dst[blue_pos] , dstAlpha, scale(dstB)), newDstAlpha); + if(allChannelFlags || channelFlags.testBit(red_pos)) + dst[red_pos] = div(blend(src[red_pos], srcAlpha, dst[red_pos], dstAlpha, scale(dstR)), newDstAlpha); + + if(allChannelFlags || channelFlags.testBit(green_pos)) + dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], dstAlpha, scale(dstG)), newDstAlpha); + + if(allChannelFlags || channelFlags.testBit(blue_pos)) + dst[blue_pos] = div(blend(src[blue_pos], srcAlpha, dst[blue_pos], dstAlpha, scale(dstB)), newDstAlpha); } return newDstAlpha; diff --git a/libs/pigment/compositeops/KoCompositeOps.h b/libs/pigment/compositeops/KoCompositeOps.h index e514e35..1258a4b 100644 --- a/libs/pigment/compositeops/KoCompositeOps.h +++ b/libs/pigment/compositeops/KoCompositeOps.h @@ -97,11 +97,12 @@ struct AddGeneralOps add<&cfScreen> (cs, COMPOSITE_SCREEN , i18n("Screen") , KoCompositeOp::categoryColor()); add<&cfOverlay>(cs, COMPOSITE_OVERLAY, i18n("Overlay"), KoCompositeOp::categoryColor()); - add<&cfArcTangent> (cs, COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent") , KoCompositeOp::categoryMisc()); - add<&cfGeometricMean>(cs, COMPOSITE_GEOMETRIC_MEAN, i18n("Geometric Mean"), KoCompositeOp::categoryMisc()); - add<&cfAllanon> (cs, COMPOSITE_ALLANON , i18n("Allanon") , KoCompositeOp::categoryMisc()); - add<&cfParallel> (cs, COMPOSITE_PARALLEL , i18n("Parallel") , KoCompositeOp::categoryMisc()); - add<&cfEquivalence> (cs, COMPOSITE_EQUIVALENCE , i18n("Equivalence") , KoCompositeOp::categoryMisc()); + add<&cfArcTangent> (cs, COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent") , KoCompositeOp::categoryMisc()); + add<&cfGeometricMean> (cs, COMPOSITE_GEOMETRIC_MEAN , i18n("Geometric Mean") , KoCompositeOp::categoryMisc()); + add<&cfAllanon> (cs, COMPOSITE_ALLANON , i18n("Allanon") , KoCompositeOp::categoryMisc()); + add<&cfParallel> (cs, COMPOSITE_PARALLEL , i18n("Parallel") , KoCompositeOp::categoryMisc()); + add<&cfEquivalence> (cs, COMPOSITE_EQUIVALENCE , i18n("Equivalence") , KoCompositeOp::categoryMisc()); + add<&cfAdditiveSubstractive>(cs, COMPOSITE_ADDITIVE_SUBSTRACTIVE, i18n("Additive-Substractive"), KoCompositeOp::categoryMisc()); } }; -- 1.7.1 From ed50155769365159baa1a3b66d5e83199cc7a8ac Mon Sep 17 00:00:00 2001 From: Silvio Heinrich Date: Wed, 12 Jan 2011 22:23:48 +0100 Subject: [PATCH 15/15] Introduced a comparison with an epsilon value in the setSaturation function. The blend modes "Saturation" and "Hue" are actually broken. Since the modes "Luminosity" and "Color" are working i expect the error somewhere in the setSaturation function. I programmed it after the ISO 32000-1 spec and cannot find where i made a mistake. --- libs/pigment/compositeops/KoCompositeOpFunctions.h | 24 ++++++++++---------- 1 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libs/pigment/compositeops/KoCompositeOpFunctions.h b/libs/pigment/compositeops/KoCompositeOpFunctions.h index c70d27e..9fb9af8 100644 --- a/libs/pigment/compositeops/KoCompositeOpFunctions.h +++ b/libs/pigment/compositeops/KoCompositeOpFunctions.h @@ -140,37 +140,37 @@ inline TReal getSaturation(TReal r, TReal g, TReal b) { template inline void setSaturation(TReal& r, TReal& g, TReal& b, TReal sat) { - TReal& min = r; - TReal& mid = g; - TReal& max = b; + TReal* min = &r; + TReal* mid = &g; + TReal* max = &b; if(mid < min) { - TReal& tmp = min; + TReal* tmp = min; min = mid; mid = tmp; } if(max < mid) { - TReal& tmp = mid; + TReal* tmp = mid; mid = max; max = tmp; } if(mid < min) { - TReal& tmp = min; + TReal* tmp = min; min = mid; mid = tmp; } - if(max > min) { - mid = ((mid-min) * sat) / (max-min); - max = sat; + if((*max - *min) > TReal(0.0001)) { + *mid = ((*mid-*min) * sat) / (*max-*min); + *max = sat; } else { - mid = TReal(0.0); - max = TReal(0.0); + *mid = TReal(0.0); + *max = TReal(0.0); } - min = TReal(0.0); + *min = TReal(0.0); } /* ---------------- Blending/Compositing functions ------------------------ / -- 1.7.1 --------------080501060900080908060607 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ kimageshop mailing list kimageshop@kde.org https://mail.kde.org/mailman/listinfo/kimageshop --------------080501060900080908060607--