[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-kimageshop
Subject:    Patch: Many composite/blend modes mostly compatible to Adobe Photoshop
From:       Silvio Heinrich <plassy () web ! de>
Date:       2011-01-12 22:17:04
Message-ID: 4D2E2860.9060107 () web ! de
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


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).

[Attachment #5 (text/html)]

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  </head>
  <body bgcolor="#ffffff" text="#000000">
    Phew... I think I've gone a bit mad with the blending modes :D.<br>
    I added a few. When counting everything together there should be
    nearly 40 compositing modes now.<br>
    All modes should trait partly transparent layers as Photoshop is
    doing it and all modes should<br>
    respect the channel flags.<br>
    But there are two problems with this patch:<br>
    <br>
    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).<br>
    I personally haven't noticed any speed impact but I've got a 3GHz
    quad core, so i think i will be the last<br>
    who will notice this.<br>
    <br>
    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:<br>
    <a class="moz-txt-link-freetext" \
href="http://www.adobe.com/devnet/pdf.html">http://www.adobe.com/devnet/pdf.html</a><br>
  <a class="moz-txt-link-freetext" \
href="http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf" \
>http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf</a>&nbsp;
> 
    (direct link)<br>
    <br>
    go to the category "Transparency" -&gt; "Basic Composition
    Computations". This spec is of course for PDFs but it seems that
    Photoshop uses the same formulas.<br>
    Since "Luminosity" and "Color" modes are working i think i made some
    mistake in implementing the<br>
    "setSat" function (on page 327). Maybe someone else has an
    enlightenment, because I'm working in the dark right now :D.<br>
    <br>
    &nbsp;But apart from this two problems everything else should work fine
    (hopefully).<span class="Apple-style-span" style="border-collapse:
      separate; color: rgb(0, 0, 0); font-family: Ubuntu; font-size:
      16px; font-style: normal; font-variant: normal; font-weight:
      normal; letter-spacing: normal; line-height: normal; orphans: 2;
      text-indent: 0px; text-transform: none; white-space: normal;
      widows: 2; word-spacing: 0px;"><span class="Apple-style-span"
        style="color: rgb(51, 51, 51); font-family:
        myriad-pro-1,myriad-pro-2,Helvetica,Arial,sans-serif; font-size:
        12px; line-height: 16px;"></span></span>
  </body>
</html>


["BlendModes.patch" (text/x-diff)]

From a2f91b86e96919ca5ff5a506933d9d798218f93f Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
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 _CSTraits>
 class KoCompositeOpBurn : public KoCompositeOpAlphaBase<_CSTraits, \
KoCompositeOpBurn<_CSTraits>, true >  {
     typedef typename _CSTraits::channels_type channels_type;
-    typedef typename KoColorSpaceMathsTraits<typename \
_CSTraits::channels_type>::compositetype compositetype; +    typedef typename \
KoColorSpaceMathsTraits<channels_type>::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<channels_type>::blend(srcColor, dstColor, \
                srcBlend);
-
-                dst[i] = newColor;
+                composite_type unitValue = \
KoColorSpaceMathsTraits<channels_type>::unitValue; +                composite_type \
invDst    = unitValue - dst[i]; +                
+                if(src[i] != KoColorSpaceMathsTraits<channels_type>::zeroValue) {
+                    composite_type result = unitValue - qMin<composite_type>(invDst \
* unitValue / src[i], unitValue); +                    dst[i] = \
KoColorSpaceMaths<channels_type>::blend(result, dst[i], srcBlend); +                }
+                else {
+                    //composite_type result = \
KoColorSpaceMathsTraits<channels_type>::zeroValue; +                    \
composite_type result = unitValue - qMin<composite_type>(invDst * unitValue, \
unitValue); +                    dst[i] = \
KoColorSpaceMaths<channels_type>::blend(result, dst[i], srcBlend); +                }
             }
         }
     }
 
-
 };
 
 #endif
-- 
1.7.1


From dd43f07e61d643153e260875276f38f33ae1af03 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
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 _CSTraits>
-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<channels_type>::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<channels_type>::unitValue;
-                composite_type invDst    = unitValue - dst[i];
-                
-                if(src[i] != KoColorSpaceMathsTraits<channels_type>::zeroValue) {
-                    composite_type result = unitValue - qMin<composite_type>(invDst \
                * unitValue / src[i], unitValue);
-                    dst[i] = KoColorSpaceMaths<channels_type>::blend(result, dst[i], \
                srcBlend);
-                }
-                else {
-                    //composite_type result = \
                KoColorSpaceMathsTraits<channels_type>::zeroValue;
-                    composite_type result = unitValue - qMin<composite_type>(invDst \
                * unitValue, unitValue);
-                    dst[i] = KoColorSpaceMaths<channels_type>::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<channels_type>::zeroValue) {
+            for(qint32 i=0; i <channels_nb; i++) {
+                if(i != alpha_pos && channelFlags.testBit(i)) {
+                    channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, \
&cfColorBurn<channels_type>); +                    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 <cberger@cberger.net>
- *
+ *  Copyright (c) 2011 Silvio Heinrich <plassy@web.de>
+ * 
  * 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 _CSTraits>
-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<typename \
_CSTraits::channels_type>::compositetype compositetype; +    typedef typename \
KoColorSpaceMathsTraits<channels_type>::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<channels_type>::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<channels_type>::zeroValue) {
+            for(qint32 i=0; i <channels_nb; i++) {
+                if(i != alpha_pos && channelFlags.testBit(i)) {
+                    channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, \
&cfColorDodge<channels_type>); +                    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 <plassy@web.de>
+ *
+ * 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 <KoColorSpaceMaths.h>
+#include <KoColorSpaceConstants.h>
+#include <KoCompositeOp.h>
+
+/* --------------------- 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<class T>
+inline T mul(T a, T b) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    return T(composite_type(a) * composite_type(b) / \
KoColorSpaceMathsTraits<T>::unitValue); +}
+
+template<class T>
+inline T mul(T a, T b, T c) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    return T((composite_type(a) * b * c) / \
(composite_type(KoColorSpaceMathsTraits<T>::unitValue) * \
KoColorSpaceMathsTraits<T>::unitValue)); +}
+
+template<class T>
+inline typename KoColorSpaceMathsTraits<T>::compositetype
+div(T a, T b) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    return composite_type(a) * KoColorSpaceMathsTraits<T>::unitValue / \
composite_type(b); +}
+
+template<class T>
+inline T inv(T a) {
+    return KoColorSpaceMathsTraits<T>::unitValue - a;
+}
+
+template<class T>
+inline T clamp(typename KoColorSpaceMathsTraits<T>::compositetype a) {
+    return (a > KoColorSpaceMathsTraits<T>::unitValue) ? \
KoColorSpaceMathsTraits<T>::unitValue : T(a); +}
+
+template<class T>
+inline T lerp(T a, T b, T alpha) {
+    return KoColorSpaceMaths<T>::blend(b, a, alpha);
+}
+
+template<class TRet, class T>
+inline TRet scale(T a) {
+    typedef typename KoColorSpaceMathsTraits<TRet>::compositetype composite_type;
+    return TRet(composite_type(a) * KoColorSpaceMathsTraits<TRet>::unitValue / \
KoColorSpaceMathsTraits<T>::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<class T>
+inline T unionShapeOpacy(T a, T b) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    return T(composite_type(a) + b - mul(a,b));
+}
+
+template<class T, class TFunc>
+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<class T>
+inline T cfColorBurn(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    
+    if(src != KoColorSpaceMathsTraits<T>::zeroValue)
+        return inv(clamp<T>(div(inv(dst), src)));
+    
+    return KoColorSpaceMathsTraits<T>::zeroValue;
+}
+
+template<class T>
+inline T cfColorDodge(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    
+    if(src != KoColorSpaceMathsTraits<T>::unitValue)
+        return clamp<T>(div(dst, inv(src)));
+    
+    return KoColorSpaceMathsTraits<T>::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 _CSTraits, class _compositeOp>
+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<bool alphaLocked>
+    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<channels_type>::unitValue;
+        channels_type opacity   = \
KoColorSpaceMaths<quint8,channels_type>::scaleToA(U8_opacity); +        
+        for(; rows>0; --rows) {
+            const channels_type* src  = reinterpret_cast<const \
channels_type*>(srcRowStart); +            channels_type*       dst  = \
reinterpret_cast<channels_type*>(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<channels_type>(*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<true>(dstRowStart, dstRowStride, srcRowStart, \
srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); +        \
else +            genericComposite<false>(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 <plassy@web.de>
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<class T>
 inline T clamp(typename KoColorSpaceMathsTraits<T>::compositetype a) {
-    return (a > KoColorSpaceMathsTraits<T>::unitValue) ? \
KoColorSpaceMathsTraits<T>::unitValue : T(a); +    typedef typename \
KoColorSpaceMathsTraits<T>::compositetype composite_type; +    return \
qBound<composite_type>(KoColorSpaceMathsTraits<T>::zeroValue, a, \
KoColorSpaceMathsTraits<T>::unitValue);  }
 
 template<class T>
@@ -89,24 +90,69 @@ inline T blend(T src, T srcAlpha, T dst, T dstAlpha, TFunc \
blendFunc) {  
 template<class T>
 inline T cfColorBurn(T src, T dst) {
-    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
-    
     if(src != KoColorSpaceMathsTraits<T>::zeroValue)
         return inv(clamp<T>(div(inv(dst), src)));
-    
     return KoColorSpaceMathsTraits<T>::zeroValue;
 }
 
 template<class T>
-inline T cfColorDodge(T src, T dst) {
+inline T cfLinearBurn(T src, T dst) {
     typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
-    
+    return clamp<T>(composite_type(src) + dst - \
KoColorSpaceMathsTraits<T>::unitValue); +}
+
+template<class T>
+inline T cfColorDodge(T src, T dst) {
     if(src != KoColorSpaceMathsTraits<T>::unitValue)
         return clamp<T>(div(dst, inv(src)));
-    
     return KoColorSpaceMathsTraits<T>::unitValue;
 }
 
+template<class T>
+inline T cfAddition(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    return clamp<T>(composite_type(src) + dst);
+}
+
+template<class T>
+inline T cfSubtract(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    return clamp<T>(composite_type(dst) - src);
+}
+
+template<class T>
+inline T cfExclusion(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    composite_type x = mul(src, dst);
+    return clamp<T>(composite_type(dst) + src - (x + x));
+}
+
+template<class T>
+inline T cfDivide(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    if(src == KoColorSpaceMathsTraits<T>::zeroValue)
+        return dst;
+    return clamp<T>(div(dst, src));
+}
+
+template<class T>
+inline T cfOver(T src, T dst) { Q_UNUSED(dst); return src; }
+
+template<class T>
+inline T cfMultiply(T src, T dst) { return mul(src, dst); }
+
+template<class T>
+inline T cfDifference(T src, T dst) { return qMax(src,dst) - qMin(src,dst); }
+
+template<class T>
+inline T cfScreen(T src, T dst) { return unionShapeOpacy(src, dst); }
+
+template<class T>
+inline T cfDarkenOnly(T src, T dst) { return qMin(src, dst); }
+
+template<class T>
+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<bool alphaLocked>
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 <plassy@web.de>
+ *
+ * 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<Traits,compositeFunc> > +{
+    typedef KoCompositeOpBase< Traits, KoCompositeOpGeneric<Traits,compositeFunc> > \
base_class; +    typedef typename Traits::channels_type                               \
channels_type; +    typedef typename \
KoColorSpaceMathsTraits<channels_type>::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<channels_type>::zeroValue) {
+            for(qint32 i=0; i <channels_nb; i++) {
+                if(i != alpha_pos && channelFlags.testBit(i)) {
+                    channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, \
compositeFunc); +                    dst[i] = div(result, newDstAlpha);
+                }
+            }
+        }
+        
+        return newDstAlpha;
+    }
+};
+
+#endif // _KOCOMPOSITEO_GENERIC_H_
diff --git a/libs/pigment/compositeops/KoCompositeOps.h \
b/libs/pigment/compositeops/KoCompositeOps.h index d278234..7949865 100644
--- a/libs/pigment/compositeops/KoCompositeOps.h
+++ b/libs/pigment/compositeops/KoCompositeOps.h
@@ -1,5 +1,6 @@
 /*
  *  Copyright (c) 2007 Cyrille Berger <cberger@cberger.net>
+ *  Copyright (c) 2011 Silvio Heinrich <plassy@web.de>
  *
  * 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<class _Traits_>
 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 <type> >(cs, \
COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix())); +    
+    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorBurn  <type> \
>(cs, COMPOSITE_BURN        , i18n("Color Burn"), KoCompositeOp::categoryLight())); + \
> cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorDodge <type> >(cs, \
> COMPOSITE_DODGE       , i18n("Color Dodge"), KoCompositeOp::categoryLight()));
+    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLinearBurn <type> \
>(cs, COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), KoCompositeOp::categoryLight())); \
> +    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition   <type> \
> >(cs, COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), \
> > KoCompositeOp::categoryLight()));
+    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDarkenOnly <type> \
>(cs, COMPOSITE_DARKEN      , i18n("Darken"), KoCompositeOp::categoryLight())); +    \
> cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLightenOnly<type> >(cs, \
> COMPOSITE_LIGHTEN     , i18n("Lighten"), KoCompositeOp::categoryLight()));
+    
+    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition  <type> >(cs, \
COMPOSITE_ADD      , i18n("Addition"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract  <type> >(cs, \
COMPOSITE_SUBTRACT , i18n("Subtract"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference<type> >(cs, \
COMPOSITE_DIFF     , i18n("Difference"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply  <type> >(cs, \
COMPOSITE_MULT     , i18n("Multiply"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide    <type> >(cs, \
COMPOSITE_DIVIDE   , i18n("Divide"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion <type> >(cs, \
COMPOSITE_EXCLUSION, i18n("Exclusion"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen    <type> >(cs, \
COMPOSITE_SCREEN   , i18n("Screen"), KoCompositeOp::categoryArithmetic()));  }
 
 #endif
-- 
1.7.1


From 2dec28d893b4f63e21f76b8039a4dd9ab236c1bc Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
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 <type> >(cs, \
                COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix()));
-- 
1.7.1


From 924c71e117c2f7ffb3151b2211fc6b7cd16f2b77 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
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 _CSTraits>
-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<channels_type>::compositetype \
                composite_type;
-    static const qint32 channels_nb = _CSTraits::channels_nb;
-    static const qint32 alpha_pos   = _CSTraits::alpha_pos;
-    
+    typedef typename KoColorSpaceMathsTraits<typename \
_CSTraits::channels_type>::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<channels_type>::zeroValue) {
-            for(qint32 i=0; i <channels_nb; i++) {
-                if(i != alpha_pos && channelFlags.testBit(i)) {
-                    channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, \
                &cfColorBurn<channels_type>);
-                    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<channels_type>::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 <cberger@cberger.net>
- *  Copyright (c) 2011 Silvio Heinrich <plassy@web.de>
- * 
+ *
  * 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 _CSTraits>
-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<channels_type>::compositetype \
                composite_type;
-    static const qint32 channels_nb = _CSTraits::channels_nb;
-    static const qint32 alpha_pos   = _CSTraits::alpha_pos;
+    typedef typename KoColorSpaceMathsTraits<typename \
_CSTraits::channels_type>::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<channels_type>::zeroValue) {
-            for(qint32 i=0; i <channels_nb; i++) {
-                if(i != alpha_pos && channelFlags.testBit(i)) {
-                    channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, \
                &cfColorDodge<channels_type>);
-                    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<channels_type>::blend(srcColor, dstColor, srcBlend); +
+                dst[channel] = newColor;
             }
         }
-        
-        return newDstAlpha;
     }
 
 };
-- 
1.7.1


From 715a106a266b5b1fda71b1fd64acc2084f411483 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
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<half>::zeroValue = 0.0;
 const half KoColorSpaceMathsTraits<half>::unitValue = 1.0;
+const half KoColorSpaceMathsTraits<half>::halfValue = 0.5;
 const half KoColorSpaceMathsTraits<half>::max = HALF_MAX;
 const half KoColorSpaceMathsTraits<half>::min = -HALF_MAX;
 const half KoColorSpaceMathsTraits<half>::epsilon = HALF_EPSILON;
@@ -34,6 +35,7 @@ const KoChannelInfo::enumChannelValueType \
KoColorSpaceMathsTraits<half>::channel  
 const float KoColorSpaceMathsTraits<float>::zeroValue = 0.0;
 const float KoColorSpaceMathsTraits<float>::unitValue = 1.0;
+const float KoColorSpaceMathsTraits<float>::halfValue = 0.5;
 const float KoColorSpaceMathsTraits<float>::max = FLT_MAX;
 const float KoColorSpaceMathsTraits<float>::min = -FLT_MAX;
 const float KoColorSpaceMathsTraits<float>::epsilon = FLT_EPSILON;
@@ -41,6 +43,7 @@ const KoChannelInfo::enumChannelValueType \
KoColorSpaceMathsTraits<float>::channe  
 const double KoColorSpaceMathsTraits<double>::zeroValue = 0.0;
 const double KoColorSpaceMathsTraits<double>::unitValue = 1.0;
+const double KoColorSpaceMathsTraits<double>::halfValue = 0.5;
 const double KoColorSpaceMathsTraits<double>::max = DBL_MAX;
 const double KoColorSpaceMathsTraits<double>::min = -DBL_MAX;
 const double KoColorSpaceMathsTraits<double>::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<class T>
+// inline T mul(T a, T b) { T(KoColorSpaceMaths<T>::multiply(a, b)); }
+
+// template<class T>
+// inline T mul(T a, T b, T c) { T(KoColorSpaceMaths<T>::multiply(a, b, c)); }
+
 template<class T>
 inline T mul(T a, T b) {
     typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
-    return T(composite_type(a) * composite_type(b) / \
KoColorSpaceMathsTraits<T>::unitValue); +    return T(composite_type(a) * b / \
KoColorSpaceMathsTraits<T>::unitValue);  }
 
 template<class T>
@@ -43,6 +49,21 @@ inline T mul(T a, T b, T c) {
 }
 
 template<class T>
+inline T inv(T a) { return KoColorSpaceMathsTraits<T>::unitValue - a; }
+
+template<class T>
+inline T lerp(T a, T b, T alpha) { return KoColorSpaceMaths<T>::blend(b, a, alpha); \
} +
+template<class TRet, class T>
+inline TRet scale(T a) { return KoColorSpaceMaths<T,TRet>::scaleToA(a); }
+
+// template<class TRet, class T>
+// inline TRet scale(T a) {
+//     typedef typename KoColorSpaceMathsTraits<TRet>::compositetype composite_type;
+//     return TRet(composite_type(a) * KoColorSpaceMathsTraits<TRet>::unitValue / \
KoColorSpaceMathsTraits<T>::unitValue); +// }
+
+template<class T>
 inline typename KoColorSpaceMathsTraits<T>::compositetype
 div(T a, T b) {
     typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
@@ -50,27 +71,11 @@ div(T a, T b) {
 }
 
 template<class T>
-inline T inv(T a) {
-    return KoColorSpaceMathsTraits<T>::unitValue - a;
-}
-
-template<class T>
 inline T clamp(typename KoColorSpaceMathsTraits<T>::compositetype a) {
     typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
     return qBound<composite_type>(KoColorSpaceMathsTraits<T>::zeroValue, a, \
KoColorSpaceMathsTraits<T>::unitValue);  }
 
-template<class T>
-inline T lerp(T a, T b, T alpha) {
-    return KoColorSpaceMaths<T>::blend(b, a, alpha);
-}
-
-template<class TRet, class T>
-inline TRet scale(T a) {
-    typedef typename KoColorSpaceMathsTraits<TRet>::compositetype composite_type;
-    return TRet(composite_type(a) * KoColorSpaceMathsTraits<TRet>::unitValue / \
                KoColorSpaceMathsTraits<T>::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<class T>
+inline T cfHardLight(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    composite_type src2 = composite_type(src) + src;
+    
+    if(src > KoColorSpaceMathsTraits<T>::halfValue) {
+        // screen(src*2.0 - 1.0, dst)
+        src2 -= KoColorSpaceMathsTraits<T>::unitValue;
+        return T((src2+dst) - (src2*dst / KoColorSpaceMathsTraits<T>::unitValue));
+    }
+    
+    // multiply(src*2.0, dst)
+    return clamp<T>(src2*dst / KoColorSpaceMathsTraits<T>::unitValue);
+}
+
+template<class T>
+inline T cfSoftLight(T src, T dst) {
+    qreal fsrc = scale<qreal>(src);
+    qreal fdst = scale<qreal>(dst);
+    
+    if(fsrc > 0.5f) {
+        qreal D = (fdst > 0.25f) ? sqrt(fdst) : ((16.0f*fdst - 12.0)*fdst + \
4.0f)*fdst; +        return scale<T>(fdst + (2.0f*fsrc - 1.0f) * (D - fdst));
+    }
+    
+    return scale<T>(fdst - (1.0f - 2.0f*fsrc) * fdst * (1.0f - fdst));
+}
+
+template<class T>
 inline T cfOver(T src, T dst) { Q_UNUSED(dst); return src; }
 
 template<class T>
+inline T cfOverlay(T src, T dst) { return cfHardLight(dst, src); }
+
+template<class T>
 inline T cfMultiply(T src, T dst) { return mul(src, dst); }
 
 template<class T>
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 <type> >(cs, \
COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix())); +    typedef typename \
_Traits_::channels_type T; +    cs->addCompositeOp(new KoCompositeOpGeneric< \
_Traits_, &cfOver<T> >(cs, COMPOSITE_OVER, i18n("Normal"), \
KoCompositeOp::categoryMix()));  
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorBurn  <type> \
                >(cs, COMPOSITE_BURN        , i18n("Color Burn"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorDodge <type> \
                >(cs, COMPOSITE_DODGE       , i18n("Color Dodge"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLinearBurn <type> \
                >(cs, COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition   <type> \
                >(cs, COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDarkenOnly <type> \
                >(cs, COMPOSITE_DARKEN      , i18n("Darken"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLightenOnly<type> \
>(cs, COMPOSITE_LIGHTEN     , i18n("Lighten"), KoCompositeOp::categoryLight())); +    \
> cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorBurn<T>   >(cs, \
> COMPOSITE_BURN        , i18n("Color Burn"), KoCompositeOp::categoryLight()));
+    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorDodge<T>  >(cs, \
COMPOSITE_DODGE       , i18n("Color Dodge"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLinearBurn<T>  >(cs, \
COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition<T>    >(cs, \
COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDarkenOnly<T>  >(cs, \
COMPOSITE_DARKEN      , i18n("Darken"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLightenOnly<T> >(cs, \
COMPOSITE_LIGHTEN     , i18n("Lighten"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfHardLight<T>   >(cs, \
COMPOSITE_HARD_LIGHT  , i18n("Hard Light"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSoftLight<T>   >(cs, \
COMPOSITE_SOFT_LIGHT  , i18n("Soft Light"), KoCompositeOp::categoryLight()));  
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition  <type> >(cs, \
                COMPOSITE_ADD      , i18n("Addition"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract  <type> >(cs, \
                COMPOSITE_SUBTRACT , i18n("Subtract"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference<type> >(cs, \
                COMPOSITE_DIFF     , i18n("Difference"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply  <type> >(cs, \
                COMPOSITE_MULT     , i18n("Multiply"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide    <type> >(cs, \
                COMPOSITE_DIVIDE   , i18n("Divide"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion <type> >(cs, \
                COMPOSITE_EXCLUSION, i18n("Exclusion"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen    <type> >(cs, \
COMPOSITE_SCREEN   , i18n("Screen"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen<T>     >(cs, \
COMPOSITE_SCREEN   , i18n("Screen"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOverlay<T>    >(cs, \
COMPOSITE_OVERLAY  , i18n("Overlay"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition<T>   >(cs, \
COMPOSITE_ADD      , i18n("Addition"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract<T>   >(cs, \
COMPOSITE_SUBTRACT , i18n("Subtract"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference<T> >(cs, \
COMPOSITE_DIFF     , i18n("Difference"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply<T>   >(cs, \
COMPOSITE_MULT     , i18n("Multiply"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide<T>     >(cs, \
COMPOSITE_DIVIDE   , i18n("Divide"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion<T>  >(cs, \
COMPOSITE_EXCLUSION, i18n("Exclusion"), KoCompositeOp::categoryArithmetic()));  }
 
 #endif
-- 
1.7.1


From 0d5c4f5a717253575c961686eb61fc5b1b60cb8e Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
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<class T>
+inline T cfVividLight(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    
+    if(src < KoColorSpaceMathsTraits<T>::halfValue) {
+        if(src == KoColorSpaceMathsTraits<T>::zeroValue)
+            return KoColorSpaceMathsTraits<T>::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<T>(KoColorSpaceMathsTraits<T>::unitValue - (dsti * \
KoColorSpaceMathsTraits<T>::unitValue / src2)); +    }
+    
+    if(src == KoColorSpaceMathsTraits<T>::unitValue)
+        return KoColorSpaceMathsTraits<T>::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<T>(composite_type(dst) * KoColorSpaceMathsTraits<T>::unitValue / \
srci2); +}
+
+template<class T>
+inline T cfPinLight(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::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<composite_type>(dst, src2);
+    composite_type b    = \
qMax<composite_type>(src2-KoColorSpaceMathsTraits<T>::unitValue, a); +    return \
T(b); +}
+
+template<class T>
+inline T cfArcTangent(T src, T dst) {
+    const static qreal pi = 3.14159265358979323846;
+    
+    if(dst == KoColorSpaceMathsTraits<T>::zeroValue)
+        return (src == KoColorSpaceMathsTraits<T>::zeroValue) ?
+            KoColorSpaceMathsTraits<T>::zeroValue : \
KoColorSpaceMathsTraits<T>::unitValue; +    
+    return scale<T>(2.0 * atan(scale<qreal>(src) / scale<qreal>(dst)) / pi);
+}
+
+template<class T>
+inline T cfGammaDark(T src, T dst) {
+    if(src == KoColorSpaceMathsTraits<T>::zeroValue)
+        return KoColorSpaceMathsTraits<T>::zeroValue;
+    
+    // power(dst, 1/src)
+    return scale<T>(pow(scale<qreal>(dst), 1.0/scale<qreal>(src)));
+}
+
+template<class T>
+inline T cfGammaLight(T src, T dst) { return scale<T>(pow(scale<qreal>(dst), \
scale<qreal>(src))); } +
+template<class T>
+inline T cfGeometricMean(T src, T dst) { return scale<T>(sqrt(scale<qreal>(dst) * \
scale<qreal>(src))); } +
+template<class T>
 inline T cfOver(T src, T dst) { Q_UNUSED(dst); return src; }
 
 template<class T>
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<T> >(cs, \
                COMPOSITE_LIGHTEN     , i18n("Lighten"), \
                KoCompositeOp::categoryLight()));
     cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfHardLight<T>   >(cs, \
                COMPOSITE_HARD_LIGHT  , i18n("Hard Light"), \
                KoCompositeOp::categoryLight()));
     cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSoftLight<T>   >(cs, \
COMPOSITE_SOFT_LIGHT  , i18n("Soft Light"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGammaLight<T>  >(cs, \
COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGammaDark<T>   >(cs, \
COMPOSITE_GAMMA_DARK  , i18n("Gamma Dark"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfVividLight<T>  >(cs, \
COMPOSITE_VIVID_LIGHT , i18n("Vivid Light"), KoCompositeOp::categoryLight())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfPinLight<T>    >(cs, \
COMPOSITE_PIN_LIGHT   , i18n("Pin Light"), KoCompositeOp::categoryLight()));  
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen<T>     >(cs, \
                COMPOSITE_SCREEN   , i18n("Screen"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOverlay<T>    >(cs, \
                COMPOSITE_OVERLAY  , i18n("Overlay"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition<T>   >(cs, \
                COMPOSITE_ADD      , i18n("Addition"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract<T>   >(cs, \
                COMPOSITE_SUBTRACT , i18n("Subtract"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference<T> >(cs, \
                COMPOSITE_DIFF     , i18n("Difference"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply<T>   >(cs, \
                COMPOSITE_MULT     , i18n("Multiply"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide<T>     >(cs, \
                COMPOSITE_DIVIDE   , i18n("Divide"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion<T>  >(cs, \
COMPOSITE_EXCLUSION, i18n("Exclusion"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen<T>        >(cs, \
COMPOSITE_SCREEN        , i18n("Screen"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOverlay<T>       >(cs, \
COMPOSITE_OVERLAY       , i18n("Overlay"), KoCompositeOp::categoryArithmetic())); +   \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition<T>      >(cs, \
COMPOSITE_ADD           , i18n("Addition"), KoCompositeOp::categoryArithmetic())); +  \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract<T>      >(cs, \
COMPOSITE_SUBTRACT      , i18n("Subtract"), KoCompositeOp::categoryArithmetic())); +  \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference<T>    >(cs, \
COMPOSITE_DIFF          , i18n("Difference"), KoCompositeOp::categoryArithmetic())); \
+    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply<T>      >(cs, \
COMPOSITE_MULT          , i18n("Multiply"), KoCompositeOp::categoryArithmetic())); +  \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide<T>        >(cs, \
COMPOSITE_DIVIDE        , i18n("Divide"), KoCompositeOp::categoryArithmetic())); +    \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion<T>     >(cs, \
COMPOSITE_EXCLUSION     , i18n("Exclusion"), KoCompositeOp::categoryArithmetic())); + \
cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfArcTangent<T>    >(cs, \
COMPOSITE_ARC_TANGENT   , i18n("Arcus Tangent"), \
KoCompositeOp::categoryArithmetic())); +    cs->addCompositeOp(new \
KoCompositeOpGeneric< _Traits_, &cfGeometricMean<T> >(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 <plassy@web.de>
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<T>::compositetype \
                a) {
     return qBound<composite_type>(KoColorSpaceMathsTraits<T>::zeroValue, a, \
KoColorSpaceMathsTraits<T>::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<class T>
@@ -88,11 +87,17 @@ inline T unionShapeOpacy(T a, T b) {
     return T(composite_type(a) + b - mul(a,b));
 }
 
-template<class T, class TFunc>
-inline T blend(T src, T srcAlpha, T dst, T dstAlpha, TFunc blendFunc) {
+template<class T, T blendFunc(T,T)>
+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<class T>
 inline T cfColorBurn(T src, T dst) {
     if(src != KoColorSpaceMathsTraits<T>::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<bool alphaLocked, bool allChannelFlags>
  *        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<bool alphaLocked>
+    template<bool alphaLocked, bool allChannelFlags>
     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<channels_type>(*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<channels_type>(*mask)) : \
opacity; +                
+                channels_type newDstAlpha = _compositeOp::template \
composeColorChannels<alphaLocked,allChannelFlags>( +                    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<true>(dstRowStart, dstRowStride, srcRowStart, \
                srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, \
                flags);
-        else
-            genericComposite<false>(dstRowStart, dstRowStride, srcRowStart, \
srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); +        \
if(alphaLocked) { +            if(allChannelFlags)
+                genericComposite<true,true>(dstRowStart, dstRowStride, srcRowStart, \
srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); +          \
else +                genericComposite<true,false>(dstRowStart, dstRowStride, \
srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, \
flags); +        }
+        else {
+            if(allChannelFlags)
+                genericComposite<false,true>(dstRowStart, dstRowStride, srcRowStart, \
srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); +          \
else +                genericComposite<false,false>(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<bool alphaLocked, bool allChannelFlags>
     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<channels_type>::zeroValue) {
             for(qint32 i=0; i <channels_nb; i++) {
-                if(i != alpha_pos && channelFlags.testBit(i)) {
-                    channels_type result = blend(src[i], srcAlpha, dst[i], dstAlpha, \
compositeFunc); +                if(i != alpha_pos && (allChannelFlags || \
channelFlags.testBit(i))) { +                    channels_type result = \
blend<channels_type,compositeFunc>(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 <plassy@web.de>
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<T>::compositetype \
                a) {
     return qBound<composite_type>(KoColorSpaceMathsTraits<T>::zeroValue, a, \
KoColorSpaceMathsTraits<T>::unitValue);  }
 
+template<class T>
+inline T min(T a, T b, T c) {
+    b = (a < b) ? a : b;
+    return (b < c) ? b : c;
+}
+
+template<class T>
+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<class T, T blendFunc(T,T)>
-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<class T>
+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<class TReal>
+inline TReal getLuminosity(TReal r, TReal g, TReal b) {
+    return TReal(0.3)*r + TReal(0.59)*g + TReal(0.11)*b;
+}
+
+template<class TReal>
+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<class TReal>
+inline TReal getSaturation(TReal r, TReal g, TReal b) {
+    return max(r,g,b) - min(r,g,b);
+}
+
+template<class TReal>
+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<class TReal>
+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<class TReal>
+inline void cfLuminosity(TReal sr, TReal sg, TReal sb, TReal& dr, TReal& dg, TReal& \
db) { +    setLuminosity(dr, dg, db, getLuminosity(sr, sg, sb));
+}
+
+template<class TReal>
+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<class TReal>
+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<class T>
 inline T cfColorBurn(T src, T dst) {
     if(src != KoColorSpaceMathsTraits<T>::zeroValue)
@@ -178,8 +294,10 @@ inline T cfVividLight(T src, T dst) {
     typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
     
     if(src < KoColorSpaceMathsTraits<T>::halfValue) {
+    
         if(src == KoColorSpaceMathsTraits<T>::zeroValue)
-            return KoColorSpaceMathsTraits<T>::zeroValue; //TODO: maybe better to \
return unitValue, must be verified +            return (dst == \
KoColorSpaceMathsTraits<T>::unitValue) ? +                \
KoColorSpaceMathsTraits<T>::unitValue : KoColorSpaceMathsTraits<T>::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<T>::unitValue)
-        return KoColorSpaceMathsTraits<T>::unitValue; //TODO: maybe better to return \
zeroValue, must be verified +        return (dst == \
KoColorSpaceMathsTraits<T>::zeroValue) ? +            \
KoColorSpaceMathsTraits<T>::zeroValue : KoColorSpaceMathsTraits<T>::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<class T>
 inline T cfPinLight(T src, T dst) {
     typedef typename KoColorSpaceMathsTraits<T>::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<composite_type>(dst, src2);
@@ -219,6 +338,40 @@ inline T cfArcTangent(T src, T dst) {
 }
 
 template<class T>
+inline T cfAllanon(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    // (dst + src) / 2   [or (dst + src) * 0.5]
+    return T((composite_type(src) + dst) * KoColorSpaceMathsTraits<T>::halfValue / \
KoColorSpaceMathsTraits<T>::unitValue); +}
+
+template<class T>
+inline T cfLinearLight(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    // min(1,max(0,(dst + 2*src)-1))
+    return clamp<T>((composite_type(src) + src + dst) - \
KoColorSpaceMathsTraits<T>::unitValue); +}
+
+template<class T>
+inline T cfParallel(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    
+    // min(max(2 / (1/dst + 1/src), 0), 1)
+    composite_type unit = KoColorSpaceMathsTraits<T>::unitValue;
+    composite_type s    = (src != KoColorSpaceMathsTraits<T>::zeroValue) ? \
div<T>(unit, src) : unit; +    composite_type d    = (dst != \
KoColorSpaceMathsTraits<T>::zeroValue) ? div<T>(unit, dst) : unit; +    
+    return clamp<T>((unit+unit) * KoColorSpaceMathsTraits<T>::unitValue / (d+s));
+}
+
+template<class T>
+inline T cfEquivalence(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    // 1 - abs(dst - src)
+    composite_type x = composite_type(dst) - src;
+    return (x < KoColorSpaceMathsTraits<T>::zeroValue) ? T(-x) : T(x);
+}
+
+template<class T>
 inline T cfGammaDark(T src, T dst) {
     if(src == KoColorSpaceMathsTraits<T>::zeroValue)
         return KoColorSpaceMathsTraits<T>::zeroValue;
@@ -350,4 +503,51 @@ public:
     }
 };
 
+
+
+
+
+template<class Traits, void compositeFunc(float, float, float, float&, float&, \
float&)> +class KoCompositeOpGenericLum : public KoCompositeOpBase< Traits, \
KoCompositeOpGenericLum<Traits,compositeFunc> > +{
+    typedef KoCompositeOpBase< Traits, KoCompositeOpGenericLum<Traits,compositeFunc> \
> 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<bool alphaLocked, bool allChannelFlags>
+    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<channels_type>::zeroValue) {
+            float srcR = scale<float>(src[red_pos]);
+            float srcG = scale<float>(src[green_pos]);
+            float srcB = scale<float>(src[blue_pos]);
+            
+            float dstR = scale<float>(dst[red_pos]);
+            float dstG = scale<float>(dst[green_pos]);
+            float dstB = scale<float>(dst[blue_pos]);
+            
+            compositeFunc(srcR, srcG, srcB, dstR, dstG, dstB);
+            dst[red_pos]   = div(blend(src[red_pos]  , srcAlpha, dst[red_pos]  , \
dstAlpha, scale<channels_type>(dstR)), newDstAlpha); +            dst[green_pos] = \
div(blend(src[green_pos], srcAlpha, dst[green_pos], dstAlpha, \
scale<channels_type>(dstG)), newDstAlpha); +            dst[blue_pos]  = \
div(blend(src[blue_pos] , srcAlpha, dst[blue_pos] , dstAlpha, \
scale<channels_type>(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<channels_type>::zeroValue) {
             for(qint32 i=0; i <channels_nb; i++) {
                 if(i != alpha_pos && (allChannelFlags || channelFlags.testBit(i))) {
-                    channels_type result = \
blend<channels_type,compositeFunc>(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 <boost/type_traits.hpp>
+
 #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<class Traits, bool flag>
+struct AddGeneralOps
+{
+    static void add(KoColorSpace* cs) { Q_UNUSED(cs); }
+};
+
+template<class Traits>
+struct AddGeneralOps<Traits, true>
+{
+    typedef typename Traits::channels_type Arg;
+    
+    template<Arg compositeFunc(Arg, Arg)>
+    static void add(KoColorSpace* cs, const QString& id, const QString& description, \
const QString& category, bool userVisible=true) { +        cs->addCompositeOp(new \
KoCompositeOpGeneric<Traits, compositeFunc>(cs, id, description, category, \
userVisible)); +    }
+    
+    static void add(KoColorSpace* cs) {
+        cs->addCompositeOp(new KoCompositeOpAlphaDarken<Traits>(cs));
+        cs->addCompositeOp(new KoCompositeOpCopy2<Traits>(cs));
+        cs->addCompositeOp(new KoCompositeOpErase<Traits>(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<class Traits, bool flag>
+struct AddHSLOps
+{
+    static void add(KoColorSpace* cs) { Q_UNUSED(cs); }
+};
+
+template<class Traits>
+struct AddHSLOps<Traits, true>
+{
+    typedef float Arg;
+    
+    template<void compositeFunc(Arg, Arg, Arg, Arg&, Arg&, Arg&)>
+    static void add(KoColorSpace* cs, const QString& id, const QString& description, \
const QString& category, bool userVisible=true) { +        cs->addCompositeOp(new \
KoCompositeOpGenericLum<Traits, compositeFunc>(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<class _Traits_>
 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<T> >(cs, \
COMPOSITE_OVER, i18n("Normal"), KoCompositeOp::categoryMix())); +    typedef typename \
_Traits_::channels_type channels_type;  
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorBurn<T>   >(cs, \
                COMPOSITE_BURN        , i18n("Color Burn"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfColorDodge<T>  >(cs, \
                COMPOSITE_DODGE       , i18n("Color Dodge"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLinearBurn<T>  >(cs, \
                COMPOSITE_LINEAR_BURN , i18n("Linear Burn"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition<T>    >(cs, \
                COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDarkenOnly<T>  >(cs, \
                COMPOSITE_DARKEN      , i18n("Darken"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfLightenOnly<T> >(cs, \
                COMPOSITE_LIGHTEN     , i18n("Lighten"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfHardLight<T>   >(cs, \
                COMPOSITE_HARD_LIGHT  , i18n("Hard Light"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSoftLight<T>   >(cs, \
                COMPOSITE_SOFT_LIGHT  , i18n("Soft Light"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGammaLight<T>  >(cs, \
                COMPOSITE_GAMMA_LIGHT , i18n("Gamma Light"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGammaDark<T>   >(cs, \
                COMPOSITE_GAMMA_DARK  , i18n("Gamma Dark"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfVividLight<T>  >(cs, \
                COMPOSITE_VIVID_LIGHT , i18n("Vivid Light"), \
                KoCompositeOp::categoryLight()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfPinLight<T>    >(cs, \
COMPOSITE_PIN_LIGHT   , i18n("Pin Light"), KoCompositeOp::categoryLight())); +    \
static const bool useGeneralOps = true; +    static const bool useHSLOps     = \
boost::is_base_of<KoRgbTraits<channels_type>, _Traits_>::value;  
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfScreen<T>        >(cs, \
                COMPOSITE_SCREEN        , i18n("Screen"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfOverlay<T>       >(cs, \
                COMPOSITE_OVERLAY       , i18n("Overlay"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfAddition<T>      >(cs, \
                COMPOSITE_ADD           , i18n("Addition"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfSubtract<T>      >(cs, \
                COMPOSITE_SUBTRACT      , i18n("Subtract"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDifference<T>    >(cs, \
                COMPOSITE_DIFF          , i18n("Difference"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfMultiply<T>      >(cs, \
                COMPOSITE_MULT          , i18n("Multiply"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfDivide<T>        >(cs, \
                COMPOSITE_DIVIDE        , i18n("Divide"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfExclusion<T>     >(cs, \
                COMPOSITE_EXCLUSION     , i18n("Exclusion"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfArcTangent<T>    >(cs, \
COMPOSITE_ARC_TANGENT   , i18n("Arcus Tangent"), \
                KoCompositeOp::categoryArithmetic()));
-    cs->addCompositeOp(new KoCompositeOpGeneric< _Traits_, &cfGeometricMean<T> >(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 <plassy@web.de>
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<KoRgbU16Traits>(this);
 
-    addCompositeOp(new RgbCompositeOpDarken<KoRgbU16Traits>(this));
-    addCompositeOp(new RgbCompositeOpLighten<KoRgbU16Traits>(this));
-    addCompositeOp(new RgbCompositeOpHue<KoRgbU16Traits>(this));
-    addCompositeOp(new RgbCompositeOpSaturation<KoRgbU16Traits>(this));
+//     addCompositeOp(new RgbCompositeOpDarken<KoRgbU16Traits>(this));
+//     addCompositeOp(new RgbCompositeOpLighten<KoRgbU16Traits>(this));
+//     addCompositeOp(new RgbCompositeOpHue<KoRgbU16Traits>(this));
+//     addCompositeOp(new RgbCompositeOpSaturation<KoRgbU16Traits>(this));
     addCompositeOp(new RgbCompositeOpValue<KoRgbU16Traits>(this));
-    addCompositeOp(new RgbCompositeOpColor<KoRgbU16Traits>(this));
+//     addCompositeOp(new RgbCompositeOpColor<KoRgbU16Traits>(this));
     addCompositeOp(new RgbCompositeOpIn<KoRgbU16Traits>(this));
     addCompositeOp(new RgbCompositeOpOut<KoRgbU16Traits>(this));
-    addCompositeOp(new RgbCompositeOpDiff<KoRgbU16Traits>(this));
+//     addCompositeOp(new RgbCompositeOpDiff<KoRgbU16Traits>(this));
     addCompositeOp(new RgbCompositeOpBumpmap<KoRgbU16Traits>(this));
 //     addCompositeOp(new RgbCompositeOpClear<KoRgbU16Traits>(this));
     addCompositeOp(new RgbCompositeOpDissolve<KoRgbU16Traits>(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<KoRgbU8Traits>(this);
 
-    addCompositeOp(new RgbCompositeOpDarken<KoRgbU8Traits>(this));
-    addCompositeOp(new RgbCompositeOpLighten<KoRgbU8Traits>(this));
-    addCompositeOp(new RgbCompositeOpHue<KoRgbU8Traits>(this));
-    addCompositeOp(new RgbCompositeOpSaturation<KoRgbU8Traits>(this));
+//     addCompositeOp(new RgbCompositeOpDarken<KoRgbU8Traits>(this));
+//     addCompositeOp(new RgbCompositeOpLighten<KoRgbU8Traits>(this));
+//     addCompositeOp(new RgbCompositeOpHue<KoRgbU8Traits>(this));
+//     addCompositeOp(new RgbCompositeOpSaturation<KoRgbU8Traits>(this));
     addCompositeOp(new RgbCompositeOpValue<KoRgbU8Traits>(this));
-    addCompositeOp(new RgbCompositeOpColor<KoRgbU8Traits>(this));
+//     addCompositeOp(new RgbCompositeOpColor<KoRgbU8Traits>(this));
     addCompositeOp(new RgbCompositeOpIn<KoRgbU8Traits>(this));
     addCompositeOp(new RgbCompositeOpOut<KoRgbU8Traits>(this));
-    addCompositeOp(new RgbCompositeOpDiff<KoRgbU8Traits>(this));
+//     addCompositeOp(new RgbCompositeOpDiff<KoRgbU8Traits>(this));
     addCompositeOp(new RgbCompositeOpBumpmap<KoRgbU8Traits>(this));
 //     addCompositeOp(new RgbCompositeOpClear<KoRgbU8Traits>(this));
     addCompositeOp(new RgbCompositeOpDissolve<KoRgbU8Traits>(this));
-- 
1.7.1


From 37204ed91a366b5ba985a274bbfff0f62d1891a9 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
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 <plassy@web.de>
+ *
+ * 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 <KoCompositeOp.h>
+#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<bool alphaLocked, bool allChannelFlags>
+ *        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 _CSTraits, class _compositeOp>
+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<bool alphaLocked, bool allChannelFlags>
+    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<channels_type>::unitValue;
+        channels_type opacity   = \
KoColorSpaceMaths<quint8,channels_type>::scaleToA(U8_opacity); +        
+        for(; rows>0; --rows) {
+            const channels_type* src  = reinterpret_cast<const \
channels_type*>(srcRowStart); +            channels_type*       dst  = \
reinterpret_cast<channels_type*>(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<channels_type>(*mask)) : opacity; +                
+                channels_type newDstAlpha = _compositeOp::template \
composeColorChannels<alphaLocked,allChannelFlags>( +                    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<true,true>(dstRowStart, dstRowStride, srcRowStart, \
srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); +          \
else +                genericComposite<true,false>(dstRowStart, dstRowStride, \
srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, \
flags); +        }
+        else {
+            if(allChannelFlags)
+                genericComposite<false,true>(dstRowStart, dstRowStride, srcRowStart, \
srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, flags); +          \
else +                genericComposite<false,false>(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 <KoColorSpaceMaths.h>
-#include <KoColorSpaceConstants.h>
-#include <KoCompositeOp.h>
 
 /* --------------------- 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<class T>
 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<bool alphaLocked, bool allChannelFlags>
- *        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 _CSTraits, class _compositeOp>
-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<bool alphaLocked, bool allChannelFlags>
-    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<channels_type>::unitValue;
-        channels_type opacity   = \
                KoColorSpaceMaths<quint8,channels_type>::scaleToA(U8_opacity);
-        
-        for(; rows>0; --rows) {
-            const channels_type* src  = reinterpret_cast<const \
                channels_type*>(srcRowStart);
-            channels_type*       dst  = \
                reinterpret_cast<channels_type*>(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<channels_type>(*mask)) : opacity;
-                
-                channels_type newDstAlpha = _compositeOp::template \
                composeColorChannels<alphaLocked,allChannelFlags>(
-                    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<true,true>(dstRowStart, dstRowStride, srcRowStart, \
                srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, \
                flags);
-            else
-                genericComposite<true,false>(dstRowStart, dstRowStride, srcRowStart, \
                srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, \
                flags);
-        }
-        else {
-            if(allChannelFlags)
-                genericComposite<false,true>(dstRowStart, dstRowStride, srcRowStart, \
                srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, \
                flags);
-            else
-                genericComposite<false,false>(dstRowStart, dstRowStride, \
srcRowStart, srcRowStride, maskRowStart, maskRowStride, rows, cols, U8_opacity, \
                flags);
-        }
-    }
-};
-
-
-
-
-
-template<class Traits, void compositeFunc(float, float, float, float&, float&, \
                float&)>
-class KoCompositeOpGenericLum : public KoCompositeOpBase< Traits, \
                KoCompositeOpGenericLum<Traits,compositeFunc> >
-{
-    typedef KoCompositeOpBase< Traits, KoCompositeOpGenericLum<Traits,compositeFunc> \
>                 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<bool alphaLocked, bool allChannelFlags>
-    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<channels_type>::zeroValue) {
-            float srcR = scale<float>(src[red_pos]);
-            float srcG = scale<float>(src[green_pos]);
-            float srcB = scale<float>(src[blue_pos]);
-            
-            float dstR = scale<float>(dst[red_pos]);
-            float dstG = scale<float>(dst[green_pos]);
-            float dstB = scale<float>(dst[blue_pos]);
-            
-            compositeFunc(srcR, srcG, srcB, dstR, dstG, dstB);
-            dst[red_pos]   = div(blend(src[red_pos]  , srcAlpha, dst[red_pos]  , \
                dstAlpha, scale<channels_type>(dstR)), newDstAlpha);
-            dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], \
                dstAlpha, scale<channels_type>(dstG)), newDstAlpha);
-            dst[blue_pos]  = div(blend(src[blue_pos] , srcAlpha, dst[blue_pos] , \
                dstAlpha, scale<channels_type>(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<Traits,compositeFunc> > +class KoCompositeOpGenericSC: public \
KoCompositeOpBase< Traits, KoCompositeOpGenericSC<Traits,compositeFunc> >  {
-    typedef KoCompositeOpBase< Traits, KoCompositeOpGeneric<Traits,compositeFunc> > \
                base_class;
-    typedef typename Traits::channels_type                                          \
                channels_type;
-    typedef typename KoColorSpaceMathsTraits<channels_type>::compositetype          \
composite_type; +    typedef KoCompositeOpBase< Traits, \
KoCompositeOpGenericSC<Traits,compositeFunc> > base_class; +    typedef typename \
Traits::channels_type                                            channels_type; +    \
typedef typename KoColorSpaceMathsTraits<channels_type>::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 Traits, void compositeFunc(float, float, float, float&, float&, \
float&)> +class KoCompositeOpGenericHSL: public KoCompositeOpBase< Traits, \
KoCompositeOpGenericHSL<Traits,compositeFunc> > +{
+    typedef KoCompositeOpBase< Traits, KoCompositeOpGenericHSL<Traits,compositeFunc> \
> 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<bool alphaLocked, bool allChannelFlags>
+    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<channels_type>::zeroValue) {
+            float srcR = scale<float>(src[red_pos]);
+            float srcG = scale<float>(src[green_pos]);
+            float srcB = scale<float>(src[blue_pos]);
+            
+            float dstR = scale<float>(dst[red_pos]);
+            float dstG = scale<float>(dst[green_pos]);
+            float dstB = scale<float>(dst[blue_pos]);
+            
+            compositeFunc(srcR, srcG, srcB, dstR, dstG, dstB);
+            
+            dst[red_pos]   = div(blend(src[red_pos]  , srcAlpha, dst[red_pos]  , \
dstAlpha, scale<channels_type>(dstR)), newDstAlpha); +            dst[green_pos] = \
div(blend(src[green_pos], srcAlpha, dst[green_pos], dstAlpha, \
scale<channels_type>(dstG)), newDstAlpha); +            dst[blue_pos]  = \
div(blend(src[blue_pos] , srcAlpha, dst[blue_pos] , dstAlpha, \
scale<channels_type>(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<Traits, true>
     
     template<Arg compositeFunc(Arg, Arg)>
     static void add(KoColorSpace* cs, const QString& id, const QString& description, \
                const QString& category, bool userVisible=true) {
-        cs->addCompositeOp(new KoCompositeOpGeneric<Traits, compositeFunc>(cs, id, \
description, category, userVisible)); +        cs->addCompositeOp(new \
KoCompositeOpGenericSC<Traits, compositeFunc>(cs, id, description, category, \
userVisible));  }
     
     static void add(KoColorSpace* cs) {
@@ -115,7 +114,7 @@ struct AddHSLOps<Traits, true>
     
     template<void compositeFunc(Arg, Arg, Arg, Arg&, Arg&, Arg&)>
     static void add(KoColorSpace* cs, const QString& id, const QString& description, \
                const QString& category, bool userVisible=true) {
-        cs->addCompositeOp(new KoCompositeOpGenericLum<Traits, compositeFunc>(cs, \
id, description, category, userVisible)); +        cs->addCompositeOp(new \
KoCompositeOpGenericHSL<Traits, compositeFunc>(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 <plassy@web.de>
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 <plassy@web.de>
+ *
+ * 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 Traits, qint32 channel_pos>
+class KoCompositeOpCopyChannel: public KoCompositeOpBase< Traits, \
KoCompositeOpCopyChannel<Traits,channel_pos> > +{
+    typedef KoCompositeOpBase< Traits, KoCompositeOpCopyChannel<Traits,channel_pos> \
> base_class; +    typedef typename Traits::channels_type                             \
> channels_type;
+    typedef typename KoColorSpaceMathsTraits<channels_type>::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<bool alphaLocked, bool allChannelFlags>
+    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<class T>
+inline T cfGrainMerge(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    return clamp<T>(composite_type(dst) + src - \
KoColorSpaceMathsTraits<T>::halfValue); +}
+
+template<class T>
+inline T cfGrainExtract(T src, T dst) {
+    typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
+    return clamp<T>(composite_type(dst) - src + \
KoColorSpaceMathsTraits<T>::halfValue); +}
+
+template<class T>
+inline T cfHardMix(T src, T dst) {
+    if(dst > KoColorSpaceMathsTraits<T>::halfValue)
+        return cfColorDodge(src, dst);
+    
+    return cfColorBurn(src, dst);
+}
+
+template<class T>
 inline T cfGammaDark(T src, T dst) {
     if(src == KoColorSpaceMathsTraits<T>::zeroValue)
         return KoColorSpaceMathsTraits<T>::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<Traits, true>
     }
     
     static void add(KoColorSpace* cs) {
+        cs->addCompositeOp(new KoCompositeOpOver<Traits>(cs));
         cs->addCompositeOp(new KoCompositeOpAlphaDarken<Traits>(cs));
         cs->addCompositeOp(new KoCompositeOpCopy2<Traits>(cs));
         cs->addCompositeOp(new KoCompositeOpErase<Traits>(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<Traits, \
true>  };
 
 template<class Traits, bool flag>
-struct AddHSLOps
+struct AddRGBOps
 {
     static void add(KoColorSpace* cs) { Q_UNUSED(cs); }
 };
 
 template<class Traits>
-struct AddHSLOps<Traits, true>
+struct AddRGBOps<Traits, true>
 {
     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<void compositeFunc(Arg, Arg, Arg, Arg&, Arg&, Arg&)>
     static void add(KoColorSpace* cs, const QString& id, const QString& description, \
                const QString& category, bool userVisible=true) {
         cs->addCompositeOp(new KoCompositeOpGenericHSL<Traits, compositeFunc>(cs, \
id, description, category, userVisible));  }
     
     static void add(KoColorSpace* cs) {
+        cs->addCompositeOp(new KoCompositeOpCopyChannel<Traits,red_pos  >(cs, \
COMPOSITE_COPY_RED  , i18n("Copy Red")  , KoCompositeOp::categoryMisc())); +        \
cs->addCompositeOp(new KoCompositeOpCopyChannel<Traits,green_pos>(cs, \
COMPOSITE_COPY_GREEN, i18n("Copy Green"), KoCompositeOp::categoryMisc())); +        \
cs->addCompositeOp(new KoCompositeOpCopyChannel<Traits,blue_pos >(cs, \
COMPOSITE_COPY_BLUE , i18n("Copy Blue") , KoCompositeOp::categoryMisc())); +        
+        if(alpha_pos != -1)
+            cs->addCompositeOp(new KoCompositeOpCopyChannel<Traits,alpha_pos>(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<KoRgbTraits<channels_type>, \
_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 <plassy@web.de>
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<class T>
 inline T cfColorBurn(T src, T dst) {
-    if(src != KoColorSpaceMathsTraits<T>::zeroValue)
-        return inv(clamp<T>(div(inv(dst), src)));
-    return KoColorSpaceMathsTraits<T>::zeroValue;
+    if(dst == KoColorSpaceMathsTraits<T>::unitValue)
+        return KoColorSpaceMathsTraits<T>::unitValue;
+    
+    T invDst = inv(dst);
+    
+    if(src < invDst)
+        return KoColorSpaceMathsTraits<T>::zeroValue;
+    
+    return inv(clamp<T>(div(invDst, src)));
 }
 
 template<class T>
@@ -227,9 +233,15 @@ inline T cfLinearBurn(T src, T dst) {
 
 template<class T>
 inline T cfColorDodge(T src, T dst) {
-    if(src != KoColorSpaceMathsTraits<T>::unitValue)
-        return clamp<T>(div(dst, inv(src)));
-    return KoColorSpaceMathsTraits<T>::unitValue;
+    if(dst == KoColorSpaceMathsTraits<T>::zeroValue)
+        return KoColorSpaceMathsTraits<T>::zeroValue;
+    
+    T invSrc = inv(src);
+    
+    if(invSrc < dst)
+        return KoColorSpaceMathsTraits<T>::unitValue;
+    
+    return clamp<T>(div(dst, invSrc));
 }
 
 template<class T>
-- 
1.7.1


From 658c78659c9f17c37d12c8f99ad3d1fbcdbe4df9 Mon Sep 17 00:00:00 2001
From: Silvio Heinrich <plassy@web.de>
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<class T>
 inline T cfDivide(T src, T dst) {
     typedef typename KoColorSpaceMathsTraits<T>::compositetype composite_type;
     if(src == KoColorSpaceMathsTraits<T>::zeroValue)
-        return dst;
+        return (dst == KoColorSpaceMathsTraits<T>::zeroValue) ?
+            KoColorSpaceMathsTraits<T>::zeroValue : \
KoColorSpaceMathsTraits<T>::unitValue; +    
     return clamp<T>(div(dst, src));
 }
 
@@ -402,6 +404,13 @@ inline T cfHardMix(T src, T dst) {
 }
 
 template<class T>
+inline T cfAdditiveSubstractive(T src, T dst) {
+    // min(1,max(0,abs(sqr(CB)-sqr(CT))))
+    qreal x = sqrt(scale<qreal>(dst)) - sqrt(scale<qreal>(src));
+    return scale<T>((x < 0.0) ? -x : x);
+}
+
+template<class T>
 inline T cfGammaDark(T src, T dst) {
     if(src == KoColorSpaceMathsTraits<T>::zeroValue)
         return KoColorSpaceMathsTraits<T>::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<channels_type>(dstR)), newDstAlpha);
-            dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], \
                dstAlpha, scale<channels_type>(dstG)), newDstAlpha);
-            dst[blue_pos]  = div(blend(src[blue_pos] , srcAlpha, dst[blue_pos] , \
dstAlpha, scale<channels_type>(dstB)), newDstAlpha); +            if(allChannelFlags \
|| channelFlags.testBit(red_pos)) +                dst[red_pos] = \
div(blend(src[red_pos], srcAlpha, dst[red_pos], dstAlpha, \
scale<channels_type>(dstR)), newDstAlpha); +            
+            if(allChannelFlags || channelFlags.testBit(green_pos))
+                dst[green_pos] = div(blend(src[green_pos], srcAlpha, dst[green_pos], \
dstAlpha, scale<channels_type>(dstG)), newDstAlpha); +            
+            if(allChannelFlags || channelFlags.testBit(blue_pos))
+                dst[blue_pos] = div(blend(src[blue_pos], srcAlpha, dst[blue_pos], \
dstAlpha, scale<channels_type>(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<Traits, true>
         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 <plassy@web.de>
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<class TReal>
 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



_______________________________________________
kimageshop mailing list
kimageshop@kde.org
https://mail.kde.org/mailman/listinfo/kimageshop


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic