[calligra/calligra/2.9] /: [FEATURE] Implemented a composite RGB curve for Curves filter

Dmitry Kazakov dimula73 at gmail.com
Thu Jun 11 15:45:49 UTC 2015


Git commit a8531cb0adf2f6ed65acfdb758b16d5f51e2898c by Dmitry Kazakov.
Committed on 11/06/2015 at 15:34.
Pushed by dkazakov into branch 'calligra/2.9'.

[FEATURE] Implemented a composite RGB curve for Curves filter

Now the curves filter provides two ways of adjusting image brightness:

1) Adjusting a grouped RGB curve
2) Adjusting L channel of Lab separation of the image using 'Lightness'
   curve

http://nonaynever.ru/kwiki/krita/published/L_vs_RGB_curve_comparison

Ref T352
CC:kimageshop at kde.org

M  +59   -27   krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp
M  +21   -4    krita/plugins/filters/colorsfilters/virtual_channel_info.cpp
M  +11   -2    krita/plugins/filters/colorsfilters/virtual_channel_info.h
M  +37   -1    libs/pigment/KoCompositeColorTransformation.cpp
M  +2    -0    libs/pigment/KoCompositeColorTransformation.h
M  +6    -2    plugins/colorengines/lcms2/LcmsColorSpace.h

http://commits.kde.org/calligra/a8531cb0adf2f6ed65acfdb758b16d5f51e2898c

diff --git a/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp
index 6bdc828..e9aa307 100644
--- a/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp
+++ b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp
@@ -57,13 +57,15 @@ QVector<VirtualChannelInfo> getVirtualChannels(const KoColorSpace *cs)
     QList<KoChannelInfo *> sortedChannels =
         KoChannelInfo::displayOrderSorted(cs->channels());
 
-    vchannels << VirtualChannelInfo(VirtualChannelInfo::LIGHTNESS, -1, 0);
+    vchannels << VirtualChannelInfo(VirtualChannelInfo::ALL_COLORS, -1, 0, cs);
 
     foreach(KoChannelInfo *channel, sortedChannels) {
         int pixelIndex = KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), sortedChannels);
-        vchannels << VirtualChannelInfo(VirtualChannelInfo::REAL, pixelIndex, channel);
+        vchannels << VirtualChannelInfo(VirtualChannelInfo::REAL, pixelIndex, channel, cs);
     }
 
+    vchannels << VirtualChannelInfo(VirtualChannelInfo::LIGHTNESS, -1, 0, cs);
+
     return vchannels;
 }
 
@@ -481,60 +483,90 @@ KoColorTransformation* KisPerChannelFilter::createTransformation(const KoColorSp
 
     bool colorsNull = true;
     bool lightnessNull = true;
+    bool allColorsNull = true;
+    int alphaIndexInReal = -1;
 
     QVector<QVector<quint16> > realTransfers;
-    QVector<quint16> lightnessTansfer;
+    QVector<quint16> lightnessTransfer;
+    QVector<quint16> allColorsTransfer;
+
     for (int i = 0; i < virtualChannels.size(); i++) {
         if (virtualChannels[i].type() == VirtualChannelInfo::REAL) {
             realTransfers << originalTransfers[i];
+
+            if (virtualChannels[i].isAlpha()) {
+                alphaIndexInReal = realTransfers.size() - 1;
+            }
+
             if (colorsNull && !originalCurves[i].isNull()) {
                 colorsNull = false;
             }
         } else if (virtualChannels[i].type() == VirtualChannelInfo::LIGHTNESS) {
-            KIS_ASSERT_RECOVER_NOOP(lightnessTansfer.isEmpty());
-            lightnessTansfer = originalTransfers[i];
+            KIS_ASSERT_RECOVER_NOOP(lightnessTransfer.isEmpty());
+            lightnessTransfer = originalTransfers[i];
 
             if (lightnessNull && !originalCurves[i].isNull()) {
                 lightnessNull = false;
             }
-        }
-    }
+        } else if (virtualChannels[i].type() == VirtualChannelInfo::ALL_COLORS) {
+            KIS_ASSERT_RECOVER_NOOP(allColorsTransfer.isEmpty());
+            allColorsTransfer = originalTransfers[i];
 
-    const quint16** transfers = new const quint16*[configBC->curves().size()];
-    for(int i = 0; i < realTransfers.size(); ++i) {
-        transfers[i] = realTransfers[i].constData();
+            if (allColorsNull && !originalCurves[i].isNull()) {
+                allColorsNull = false;
+            }
+        }
     }
 
     KoColorTransformation *lightnessTransform = 0;
+    KoColorTransformation *allColorsTransform = 0;
     KoColorTransformation *colorTransform = 0;
 
     if (!colorsNull) {
+        const quint16** transfers = new const quint16*[realTransfers.size()];
+        for(int i = 0; i < realTransfers.size(); ++i) {
+            transfers[i] = realTransfers[i].constData();
+
+            /**
+             * createPerChannelAdjustment() expects alpha channel to
+             * be the last channel in the list, so just it here
+             */
+            KIS_ASSERT_RECOVER_NOOP(i != alphaIndexInReal ||
+                                    alphaIndexInReal == (realTransfers.size() - 1));
+        }
+
         colorTransform = cs->createPerChannelAdjustment(transfers);
+        delete [] transfers;
     }
 
     if (!lightnessNull) {
-        lightnessTransform = cs->createBrightnessContrastAdjustment(lightnessTansfer.constData());
+        lightnessTransform = cs->createBrightnessContrastAdjustment(lightnessTransfer.constData());
     }
 
-    KoColorTransformation *finalTransform = 0;
-
-    if (colorTransform && lightnessTransform) {
-        KoCompositeColorTransformation *compositeTransform =
-            new KoCompositeColorTransformation(
-                KoCompositeColorTransformation::INPLACE);
-
-        compositeTransform->appendTransform(colorTransform);
-        compositeTransform->appendTransform(lightnessTransform);
+    if (!allColorsNull) {
+        const quint16** allColorsTransfers = new const quint16*[realTransfers.size()];
+        for(int i = 0; i < realTransfers.size(); ++i) {
+            allColorsTransfers[i] = (i != alphaIndexInReal) ?
+                allColorsTransfer.constData() : 0;
+
+            /**
+             * createPerChannelAdjustment() expects alpha channel to
+             * be the last channel in the list, so just it here
+             */
+            KIS_ASSERT_RECOVER_NOOP(i != alphaIndexInReal ||
+                                    alphaIndexInReal == (realTransfers.size() - 1));
+        }
 
-        finalTransform = compositeTransform;
-    } else if (lightnessTransform) {
-        finalTransform = lightnessTransform;
-    } else  if (colorTransform) {
-        finalTransform = colorTransform;
+        allColorsTransform = cs->createPerChannelAdjustment(allColorsTransfers);
+        delete[] allColorsTransfers;
     }
 
-    delete [] transfers;
-    return finalTransform;
+    QVector<KoColorTransformation*> allTransforms;
+    allTransforms << lightnessTransform;
+    allTransforms << allColorsTransform;
+    allTransforms << colorTransform;
+
+    return KoCompositeColorTransformation::createOptimizedCompositeTransform(allTransforms);
 }
 
 #include "kis_perchannel_filter.moc"
diff --git a/krita/plugins/filters/colorsfilters/virtual_channel_info.cpp b/krita/plugins/filters/colorsfilters/virtual_channel_info.cpp
index aae5806..3b042ad 100644
--- a/krita/plugins/filters/colorsfilters/virtual_channel_info.cpp
+++ b/krita/plugins/filters/colorsfilters/virtual_channel_info.cpp
@@ -19,6 +19,7 @@
 #include "virtual_channel_info.h"
 #include <klocale.h>
 
+#include <KoColorSpace.h>
 
 
 VirtualChannelInfo::VirtualChannelInfo()
@@ -30,11 +31,21 @@ VirtualChannelInfo::VirtualChannelInfo()
 
 VirtualChannelInfo::VirtualChannelInfo(Type type,
                                        int pixelIndex,
-                                       KoChannelInfo *realChannelInfo)
+                                       KoChannelInfo *realChannelInfo,
+                                       const KoColorSpace *cs)
     : m_type(type),
       m_pixelIndex(pixelIndex),
       m_realChannelInfo(realChannelInfo)
 {
+    if (m_type == LIGHTNESS) {
+        m_nameOverride = i18n("Lightness");
+        m_valueTypeOverride = KoChannelInfo::FLOAT32;
+        m_channelSizeOverride = 4;
+    } else if (m_type == ALL_COLORS) {
+        m_nameOverride = cs->colorModelId().id();
+        m_valueTypeOverride = cs->channels().first()->channelValueType();
+        m_channelSizeOverride = cs->channels().first()->size();
+    }
 }
 
 VirtualChannelInfo::Type VirtualChannelInfo::type() const {
@@ -46,7 +57,7 @@ KoChannelInfo* VirtualChannelInfo::channelInfo() const {
 }
 
 QString VirtualChannelInfo::name() const {
-    return m_type == REAL ? m_realChannelInfo->name() : i18n("Lightness");
+    return m_type == REAL ? m_realChannelInfo->name() : m_nameOverride;
 }
 
 int VirtualChannelInfo::pixelIndex() const {
@@ -54,9 +65,15 @@ int VirtualChannelInfo::pixelIndex() const {
 }
 
 KoChannelInfo::enumChannelValueType VirtualChannelInfo::valueType() const {
-    return m_type == REAL ? m_realChannelInfo->channelValueType() : KoChannelInfo::FLOAT32;
+    return m_type == REAL ? m_realChannelInfo->channelValueType() : m_valueTypeOverride;
 }
 
 int VirtualChannelInfo::channelSize() const {
-    return m_type == REAL ? m_realChannelInfo->size() : 4;
+    return m_type == REAL ? m_realChannelInfo->size() : m_channelSizeOverride;
+}
+
+bool VirtualChannelInfo::isAlpha() const
+{
+    return m_type == REAL &&
+        m_realChannelInfo->channelType() == KoChannelInfo::ALPHA;
 }
diff --git a/krita/plugins/filters/colorsfilters/virtual_channel_info.h b/krita/plugins/filters/colorsfilters/virtual_channel_info.h
index 9af3ab5..204fa8f 100644
--- a/krita/plugins/filters/colorsfilters/virtual_channel_info.h
+++ b/krita/plugins/filters/colorsfilters/virtual_channel_info.h
@@ -20,18 +20,21 @@
 #define __VIRTUAL_CHANNEL_INFO_H
 
 #include <KoChannelInfo.h>
+class KoColorSpace;
+
 
 class VirtualChannelInfo
 {
 public:
     enum Type {
         REAL,
-        LIGHTNESS
+        LIGHTNESS,
+        ALL_COLORS
     };
 
     VirtualChannelInfo();
 
-    VirtualChannelInfo(Type type, int pixelIndex, KoChannelInfo *realChannelInfo);
+    VirtualChannelInfo(Type type, int pixelIndex, KoChannelInfo *realChannelInfo, const KoColorSpace *cs);
 
     Type type() const;
     KoChannelInfo* channelInfo() const;
@@ -40,10 +43,16 @@ public:
     KoChannelInfo::enumChannelValueType valueType() const;
     int channelSize() const;
 
+    bool isAlpha() const;
+
 private:
     Type m_type;
     int m_pixelIndex;
     KoChannelInfo *m_realChannelInfo;
+
+    QString m_nameOverride;
+    KoChannelInfo::enumChannelValueType m_valueTypeOverride;
+    int m_channelSizeOverride;
 };
 
 #endif /* __VIRTUAL_CHANNEL_INFO_H */
diff --git a/libs/pigment/KoCompositeColorTransformation.cpp b/libs/pigment/KoCompositeColorTransformation.cpp
index 2de2ecf..d9bf2f1 100644
--- a/libs/pigment/KoCompositeColorTransformation.cpp
+++ b/libs/pigment/KoCompositeColorTransformation.cpp
@@ -43,7 +43,9 @@ KoCompositeColorTransformation::~KoCompositeColorTransformation()
 
 void KoCompositeColorTransformation::appendTransform(KoColorTransformation *transform)
 {
-    m_d->transformations.append(transform);
+    if (transform) {
+        m_d->transformations.append(transform);
+    }
 }
 
 void KoCompositeColorTransformation::transform(const quint8 *src, quint8 *dst, qint32 nPixels) const
@@ -60,3 +62,37 @@ void KoCompositeColorTransformation::transform(const quint8 *src, quint8 *dst, q
         }
     }
 }
+
+KoColorTransformation* KoCompositeColorTransformation::createOptimizedCompositeTransform(const QVector<KoColorTransformation*> transforms)
+{
+    KoColorTransformation *finalTransform = 0;
+
+    int numValidTransforms = 0;
+    foreach (KoColorTransformation *t, transforms) {
+        numValidTransforms += bool(t);
+    }
+
+    if (numValidTransforms > 1) {
+        KoCompositeColorTransformation *compositeTransform =
+            new KoCompositeColorTransformation(
+                KoCompositeColorTransformation::INPLACE);
+
+        foreach (KoColorTransformation *t, transforms) {
+            if (t) {
+                compositeTransform->appendTransform(t);
+            }
+        }
+
+        finalTransform = compositeTransform;
+
+    } else if (numValidTransforms == 1) {
+        foreach (KoColorTransformation *t, transforms) {
+            if (t) {
+                finalTransform = t;
+                break;
+            }
+        }
+    }
+
+    return finalTransform;
+}
diff --git a/libs/pigment/KoCompositeColorTransformation.h b/libs/pigment/KoCompositeColorTransformation.h
index 1c4bf28..020363c 100644
--- a/libs/pigment/KoCompositeColorTransformation.h
+++ b/libs/pigment/KoCompositeColorTransformation.h
@@ -40,6 +40,8 @@ public:
 
     void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const;
 
+    static KoColorTransformation* createOptimizedCompositeTransform(const QVector<KoColorTransformation*> transforms);
+
 private:
     struct Private;
     const QScopedPointer<Private> m_d;
diff --git a/plugins/colorengines/lcms2/LcmsColorSpace.h b/plugins/colorengines/lcms2/LcmsColorSpace.h
index 576fb52..bf9a262 100644
--- a/plugins/colorengines/lcms2/LcmsColorSpace.h
+++ b/plugins/colorengines/lcms2/LcmsColorSpace.h
@@ -306,11 +306,15 @@ public:
         cmsToneCurve ** transferFunctions = new cmsToneCurve*[ this->colorChannelCount()];
 
         for (uint ch = 0; ch < this->colorChannelCount(); ch++) {
-            transferFunctions[ch] = cmsBuildTabulatedToneCurve16( 0, 256, transferValues[ch]);
+            transferFunctions[ch] = transferValues[ch] ?
+                cmsBuildTabulatedToneCurve16( 0, 256, transferValues[ch]) :
+                cmsBuildGamma(0, 1.0);
         }
 
         cmsToneCurve ** alphaTransferFunctions = new cmsToneCurve*[1];
-        alphaTransferFunctions[0] = cmsBuildTabulatedToneCurve16( 0, 256, transferValues[this->colorChannelCount()]);
+        alphaTransferFunctions[0] = transferValues[this->colorChannelCount()] ?
+            cmsBuildTabulatedToneCurve16( 0, 256, transferValues[this->colorChannelCount()]) :
+            cmsBuildGamma(0, 1.0);
 
         KoLcmsColorTransformation *adj = new KoLcmsColorTransformation(this);
         adj->profiles[0] = cmsCreateLinearizationDeviceLink(this->colorSpaceSignature(), transferFunctions);



More information about the kimageshop mailing list