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

List:       kde-commits
Subject:    [calligra/calligra/2.9] /: [FEATURE] Lightness curve for per-channel filter
From:       Dmitry Kazakov <dimula73 () gmail ! com>
Date:       2015-05-30 22:15:24
Message-ID: E1Yyp2K-0002L5-69 () scm ! kde ! org
[Download RAW message or body]

Git commit 45d4e30d35c9e027021b1a6ff585c9687cf1de83 by Dmitry Kazakov.
Committed on 30/05/2015 at 22:04.
Pushed by dkazakov into branch 'calligra/2.9'.

[FEATURE] Lightness curve for per-channel filter

Now the curves filter can do everything:

1) Correct colors directly by editing RGB curves
2) Correct 'Lightness' using a special curve. Please
   not that this is not a 'RGB' curve like in Photoshop,
   it is a real Lightness curve from Lab color space.
3) Edit a curve for alpha

BUG:324332
Ref T352

M  +13   -0    krita/image/kis_cubic_curve.cpp
M  +2    -0    krita/image/kis_cubic_curve.h
M  +17   -0    krita/image/tests/kis_cubic_curve_test.cpp
M  +1    -0    krita/image/tests/kis_cubic_curve_test.h
M  +1    -0    krita/plugins/filters/colorsfilters/CMakeLists.txt
M  +156  -121  krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp
M  +7    -1    krita/plugins/filters/colorsfilters/kis_perchannel_filter.h
A  +62   -0    krita/plugins/filters/colorsfilters/virtual_channel_info.cpp     \
[License: GPL (v2+)] C  +25   -21   \
krita/plugins/filters/colorsfilters/virtual_channel_info.h [from: \
krita/image/tests/kis_cubic_curve_test.h - 053% similarity] M  +1    -0    \
libs/pigment/CMakeLists.txt A  +62   -0    \
libs/pigment/KoCompositeColorTransformation.cpp     [License: GPL (v2+)] A  +48   -0  \
libs/pigment/KoCompositeColorTransformation.h     [License: GPL (v2+)]

http://commits.kde.org/calligra/45d4e30d35c9e027021b1a6ff585c9687cf1de83

diff --git a/krita/image/kis_cubic_curve.cpp b/krita/image/kis_cubic_curve.cpp
index c19381b..8924eb7 100644
--- a/krita/image/kis_cubic_curve.cpp
+++ b/krita/image/kis_cubic_curve.cpp
@@ -406,6 +406,19 @@ void KisCubicCurve::removePoint(int idx)
     d->data->invalidate();
 }
 
+bool KisCubicCurve::isNull() const
+{
+    const QList<QPointF> &points = d->data->points;
+
+    foreach (const QPointF &pt, points) {
+        if (!qFuzzyCompare(pt.x(), pt.y())) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 const QString& KisCubicCurve::name() const
 {
     return d->data->name;
diff --git a/krita/image/kis_cubic_curve.h b/krita/image/kis_cubic_curve.h
index 1eb9371..77351dc 100644
--- a/krita/image/kis_cubic_curve.h
+++ b/krita/image/kis_cubic_curve.h
@@ -54,6 +54,8 @@ public:
     int addPoint(const QPointF& point);
     void removePoint(int idx);
 
+    bool isNull() const;
+
     /**
      * This allows us to carry around a display name for the curve internally. It is \
                used
      * currently in Sketch for perchannel, but would potentially be useful anywhere
diff --git a/krita/image/tests/kis_cubic_curve_test.cpp \
b/krita/image/tests/kis_cubic_curve_test.cpp index e934768..27f2a0e 100644
--- a/krita/image/tests/kis_cubic_curve_test.cpp
+++ b/krita/image/tests/kis_cubic_curve_test.cpp
@@ -139,6 +139,23 @@ void KisCubicCurveTest::testValue()
     }
 }
 
+void KisCubicCurveTest::testNull()
+{
+    KisCubicCurve cc;
+    QVERIFY(cc.isNull());
+
+    cc.addPoint(QPointF(0.2, 0.3));
+    QVERIFY(!cc.isNull());
+
+    QList<QPointF> points;
+    points << QPointF();
+    points << QPointF(0.2,0.2);
+    points << QPointF(1.0,1.0);
+
+    cc.setPoints(points);
+    QVERIFY(cc.isNull());
+}
+
 
 void KisCubicCurveTest::testTransfer()
 {
diff --git a/krita/image/tests/kis_cubic_curve_test.h \
b/krita/image/tests/kis_cubic_curve_test.h index 60ffaff..28c0385 100644
--- a/krita/image/tests/kis_cubic_curve_test.h
+++ b/krita/image/tests/kis_cubic_curve_test.h
@@ -36,6 +36,7 @@ private Q_SLOTS:
     void testComparison();
     void testSerialization();
     void testValue();
+    void testNull();
     void testTransfer();
 private:
     QPointF pt0, pt1, pt2, pt3, pt4, pt5;
diff --git a/krita/plugins/filters/colorsfilters/CMakeLists.txt \
b/krita/plugins/filters/colorsfilters/CMakeLists.txt index 4062dbe..d6024a6 100644
--- a/krita/plugins/filters/colorsfilters/CMakeLists.txt
+++ b/krita/plugins/filters/colorsfilters/CMakeLists.txt
@@ -3,6 +3,7 @@
 set(kritacolorsfilters_PART_SRCS
     colorsfilters.cpp
     kis_hsv_adjustment_filter.cpp
+    virtual_channel_info.cpp
     kis_perchannel_filter.cpp
     kis_brightness_contrast_filter.cpp
     kis_color_balance_filter.cpp
diff --git a/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp \
b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp index \
                55cfae9..6bdc828 100644
--- a/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp
+++ b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.cpp
@@ -33,9 +33,12 @@
 #include "KoBasicHistogramProducers.h"
 #include "KoColorSpace.h"
 #include "KoColorTransformation.h"
+#include "KoCompositeColorTransformation.h"
 #include "KoCompositeOp.h"
 #include "KoID.h"
 
+#include "kis_signals_blocker.h"
+
 #include "kis_bookmarked_configuration_manager.h"
 #include "kis_config_widget.h"
 #include <filter/kis_filter_configuration.h>
@@ -47,7 +50,22 @@
 #include "kis_painter.h"
 #include "widgets/kis_curve_widget.h"
 
+QVector<VirtualChannelInfo> getVirtualChannels(const KoColorSpace *cs)
+{
+    QVector<VirtualChannelInfo> vchannels;
+
+    QList<KoChannelInfo *> sortedChannels =
+        KoChannelInfo::displayOrderSorted(cs->channels());
+
+    vchannels << VirtualChannelInfo(VirtualChannelInfo::LIGHTNESS, -1, 0);
+
+    foreach(KoChannelInfo *channel, sortedChannels) {
+        int pixelIndex = \
KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), \
sortedChannels); +        vchannels << VirtualChannelInfo(VirtualChannelInfo::REAL, \
pixelIndex, channel); +    }
 
+    return vchannels;
+}
 
 KisPerChannelConfigWidget::KisPerChannelConfigWidget(QWidget * parent, \
KisPaintDeviceSP dev, Qt::WFlags f)  : KisConfigWidget(parent, f), m_histogram(0)
@@ -61,27 +79,22 @@ KisPerChannelConfigWidget::KisPerChannelConfigWidget(QWidget * \
parent, KisPaintD  layout->addWidget(m_page);
 
     m_dev = dev;
-    m_activeCh = 0;
+    m_activeVChannel = 0;
+
+    // fill in the channel chooser, in the display order, but store the pixel index \
as well. +
+    m_virtualChannels = getVirtualChannels(dev->colorSpace());
+    const int virtualChannelCount = m_virtualChannels.size();
 
     KisPerChannelFilterConfiguration::initDefaultCurves(m_curves,
-            m_dev->colorSpace()->channelCount());
+                                                        virtualChannelCount);
+    for (int i = 0; i < virtualChannelCount; i++) {
+        const VirtualChannelInfo &info = m_virtualChannels[i];
 
-    QList<KoChannelInfo *> colorChannels;
-    foreach(KoChannelInfo *channel, dev->colorSpace()->channels()) {
-        if (channel->channelType() == KoChannelInfo::COLOR || channel->channelType() \
                == KoChannelInfo::ALPHA) {
-            colorChannels.append(channel);
-        }
-    }
-    // fill in the channel chooser, in the display order, but store the pixel index \
                as well.
-    QList<KoChannelInfo *> sortedChannels = \
                KoChannelInfo::displayOrderSorted(colorChannels);
-    foreach(KoChannelInfo *channel, sortedChannels) {
-        QVariant pixelIndex(KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), \
                
-                                                                         \
                KoChannelInfo::displayOrderSorted(dev->colorSpace()->channels())));
-        m_page->cmbChannel->addItem(channel->name(), pixelIndex);
-        KisCubicCurve curve = m_curves[m_page->cmbChannel->count() - 1];
-        curve.setName(channel->name());
-        m_curves[m_page->cmbChannel->count() - 1] = curve;
+        m_page->cmbChannel->addItem(info.name(), info.pixelIndex());
+        m_curves[i].setName(info.name());
     }
+
     connect(m_page->cmbChannel, SIGNAL(activated(int)), this, \
SLOT(setActiveChannel(int)));  
     // create the horizontal and vertical gradient labels
@@ -91,7 +104,7 @@ KisPerChannelConfigWidget::KisPerChannelConfigWidget(QWidget * \
parent, KisPaintD  // init histogram calculator
     QList<QString> keys =
         KoHistogramProducerFactoryRegistry::instance()->keysCompatibleWith(m_dev->colorSpace());
                
-    
+
     if(keys.size() > 0) {
         KoHistogramProducerFactory *hpf;
         hpf = KoHistogramProducerFactoryRegistry::instance()->get(keys.at(0));
@@ -102,10 +115,11 @@ KisPerChannelConfigWidget::KisPerChannelConfigWidget(QWidget * \
parent, KisPaintD  
     m_page->curveWidget->setupInOutControls(m_page->intIn, m_page->intOut, 0, 100);
 
-    m_page->curveWidget->blockSignals(true);
-    m_page->curveWidget->setCurve(m_curves[0]);
-    setActiveChannel(0);
-    m_page->curveWidget->blockSignals(false);
+    {
+        KisSignalsBlocker b(m_page->curveWidget);
+        m_page->curveWidget->setCurve(m_curves[0]);
+        setActiveChannel(0);
+    }
 }
 
 KisPerChannelConfigWidget::~KisPerChannelConfigWidget()
@@ -147,9 +161,11 @@ inline QPixmap KisPerChannelConfigWidget::getHistogram()
     QPainter p(&pix);
     p.setPen(QPen(Qt::gray, 1, Qt::SolidLine));
 
-    if(m_histogram)
+    const VirtualChannelInfo &info = m_virtualChannels[m_activeVChannel];
+
+    if (m_histogram && info.type() == VirtualChannelInfo::REAL)
     {
-        m_histogram->setChannel(m_activeCh);
+        m_histogram->setChannel(info.pixelIndex());
 
         double highest = (double)m_histogram->calculations().getHighest();
         qint32 bins = m_histogram->producer()->numberOfBins();
@@ -174,22 +190,27 @@ inline QPixmap KisPerChannelConfigWidget::getHistogram()
 
 void KisPerChannelConfigWidget::setActiveChannel(int ch)
 {
-    m_curves[m_activeCh] = m_page->curveWidget->curve();
-    m_activeCh = ch;
-    m_page->curveWidget->setCurve(m_curves[m_activeCh]);
+    m_curves[m_activeVChannel] = m_page->curveWidget->curve();
+
+    m_activeVChannel = ch;
+    m_page->curveWidget->setCurve(m_curves[m_activeVChannel]);
     m_page->curveWidget->setPixmap(getHistogram());
-    m_page->cmbChannel->setCurrentIndex(ch);
+    m_page->cmbChannel->setCurrentIndex(m_activeVChannel);
+
 
     // Getting range accepted by channel
-    KoChannelInfo *channel = m_dev->colorSpace()->channels()[m_activeCh];
-    int order = BITS_PER_BYTE * channel->size();
+    VirtualChannelInfo &currentVChannel = m_virtualChannels[m_activeVChannel];
+
+    KoChannelInfo::enumChannelValueType valueType = currentVChannel.valueType();
+
+    int order = BITS_PER_BYTE * currentVChannel.channelSize();
     int maxValue = pwr2(order);
     int min;
     int max;
 
     m_page->curveWidget->dropInOutControls();
 
-    switch (channel->channelValueType()) {
+    switch (valueType) {
     case KoChannelInfo::UINT8:
     case KoChannelInfo::UINT16:
     case KoChannelInfo::UINT32:
@@ -223,13 +244,12 @@ void KisPerChannelConfigWidget::setActiveChannel(int ch)
 
 KisPropertiesConfiguration * KisPerChannelConfigWidget::configuration() const
 {
-    int nCh = m_dev->colorSpace()->channelCount();
-    KisPerChannelFilterConfiguration * cfg = new \
KisPerChannelFilterConfiguration(nCh); +    int numChannels = \
m_virtualChannels.size(); +    KisPerChannelFilterConfiguration * cfg = new \
KisPerChannelFilterConfiguration(numChannels);  
-    // updating current state
-    if (m_activeCh < m_curves.size()) {
-        m_curves[m_activeCh] = m_page->curveWidget->curve();
-    }
+    KIS_ASSERT_RECOVER(m_activeVChannel < m_curves.size()) { return cfg; }
+
+    m_curves[m_activeVChannel] = m_page->curveWidget->curve();
     cfg->setCurves(m_curves);
 
     return cfg;
@@ -245,36 +265,31 @@ void KisPerChannelConfigWidget::setConfiguration(const \
KisPropertiesConfiguratio  /**
          * HACK ALERT: our configuration factory generates
          * default configuration with nTransfers==0.
-         * Catching it here.
+         * Catching it here. Just reset all the transfers.
          */
 
+        const int virtualChannelCount = m_virtualChannels.size();
         KisPerChannelFilterConfiguration::initDefaultCurves(m_curves,
-                m_dev->colorSpace()->channelCount());
+                                                            virtualChannelCount);
 
-        // Getting the names of the color channels {
-        QList<KoChannelInfo *> colorChannels;
-        foreach(KoChannelInfo *channel, m_dev->colorSpace()->channels()) {
-            if (channel->channelType() == KoChannelInfo::COLOR || \
                channel->channelType() == KoChannelInfo::ALPHA) {
-                colorChannels.append(channel);
-            }
+        for (int i = 0; i < virtualChannelCount; i++) {
+            const VirtualChannelInfo &info = m_virtualChannels[i];
+            m_curves[i].setName(info.name());
         }
-        // Get the channel information, but listed in display order
-        QList<KoChannelInfo *> sortedChannels = \
                KoChannelInfo::displayOrderSorted(colorChannels);
-        int i = 0;
-        foreach(KoChannelInfo *channel, sortedChannels) {
-            KisCubicCurve curve = m_curves[i];
-            curve.setName(channel->name());
-            m_curves[i++] = curve;
-        }
-        // } Getting the names of the color channels
-    } else if (cfg->curves().size() != int(m_dev->colorSpace()->channelCount())) {
+
+    } else if (cfg->curves().size() != int(m_virtualChannels.size())) {
+        qWarning() << "WARNING: trying to load a curve with incorrect  number of \
channels!"; +        qWarning() << "WARNING:   expected:" << \
m_virtualChannels.size(); +        qWarning() << "WARNING:        got:" << \
cfg->curves().size();  return;
     } else {
         for (int ch = 0; ch < cfg->curves().size(); ch++)
             m_curves[ch] = cfg->curves()[ch];
     }
 
-    m_page->curveWidget->setCurve(m_curves[m_activeCh]);
+    // HACK: we save the previous curve in setActiveChannel, so just copy it
+    m_page->curveWidget->setCurve(m_curves[m_activeVChannel]);
+
     setActiveChannel(0);
 }
 
@@ -350,8 +365,6 @@ void KisPerChannelFilterConfiguration::fromXML(const QDomElement& \
root)  while (!e.isNull()) {
         if ((attributeName = e.attribute("name")) == "nTransfers") {
             numTransfers = e.text().toUShort();
-        } else if ((attributeName = e.attribute("name")) == "nTransfersWithAlpha") {
-            numTransfers = e.text().toUShort();
         } else {
             QRegExp rx("curve(\\d+)");
             if (rx.indexIn(attributeName, 0) != -1) {
@@ -364,25 +377,10 @@ void KisPerChannelFilterConfiguration::fromXML(const \
QDomElement& root)  }
                 curves.insert(index, curve);
             }
-            QRegExp rxAlphaCurve("alphaCurve");
-            if (rxAlphaCurve.indexIn(attributeName, 0) != -1) {
-                index = curves.count() + 1;
-
-                if (!e.text().isEmpty()) {
-                    curve.fromString(e.text());
-                }
-                curves.insert(index,curve);
-            }
         }
         e = e.nextSiblingElement();
     }
 
-    curve.fromString("0,0;1,1");
-    if(numTransfers == 3) {
-        numTransfers++;
-        curves.insert(index + 1, curve);
-    }
-
     if (!numTransfers)
         return;
 
@@ -395,66 +393,45 @@ void KisPerChannelFilterConfiguration::fromXML(const \
                QDomElement& root)
  */
 //void KisPerChannelFilterConfiguration::fromXML(const QString& s)
 
+void addParamNode(QDomDocument& doc,
+                  QDomElement& root,
+                  const QString &name,
+                  const QString &value)
+{
+    QDomText text = doc.createTextNode(value);
+    QDomElement t = doc.createElement("param");
+    t.setAttribute("name", name);
+    t.appendChild(text);
+    root.appendChild(t);
+}
+
 void KisPerChannelFilterConfiguration::toXML(QDomDocument& doc, QDomElement& root) \
const  {
     /**
      * <params version=1>
      *       <param name="nTransfers">3</param>
-     *       <param name="nTransfersWithAlpha">4</param>
      *       <param name="curve0">0,0;0.5,0.5;1,1;</param>
      *       <param name="curve1">0,0;1,1;</param>
      *       <param name="curve2">0,0;1,1;</param>
-     *       <param name="alphaCurve">0,0;1,1;</param>
-     *       <!-- for the future
-     *       <param name="commonCurve">0,0;1,1;</param>
-     *       -->
      * </params>
      */
 
     root.setAttribute("version", version());
 
-    QDomElement t = doc.createElement("param");
-    QDomText text, textAlpha;
-    if(m_curves.size() == 4) {
-        text = doc.createTextNode(QString::number(m_curves.size()-1));
-        textAlpha = doc.createTextNode(QString::number(m_curves.size()));
-    }
-    else {
-        text = doc.createTextNode(QString::number(m_curves.size()));
-        textAlpha = doc.createTextNode(QString::number(m_curves.size()));
-    }
+    QDomText text;
+    QDomElement t;
 
-    t.setAttribute("name", "nTransfers");
-    t.appendChild(text);
-    root.appendChild(t);
-
-    t = doc.createElement("param");
-    t.setAttribute("name", "nTransfersWithAlpha");
-    t.appendChild(textAlpha);
-    root.appendChild(t);
+    addParamNode(doc, root, "nTransfers", QString::number(m_curves.size()));
 
     KisCubicCurve curve;
     QString paramName;
 
-    for (int i = 0; i < m_curves.size() - 1; ++i) {
-        paramName = QLatin1String("curve") + QString::number(i);
-        t = doc.createElement("param");
-        t.setAttribute("name", paramName);
+    for (int i = 0; i < m_curves.size(); ++i) {
+        QString name = QLatin1String("curve") + QString::number(i);
+        QString value = m_curves[i].toString();
 
-        curve = m_curves[i];
-        text = doc.createTextNode(curve.toString());
-        t.appendChild(text);
-        root.appendChild(t);
+        addParamNode(doc, root, name, value);
     }
-
-    paramName = QLatin1String("alphaCurve");
-    t = doc.createElement("param");
-    t.setAttribute("name", paramName);
-
-    curve = m_curves[m_curves.size()-1];
-    text = doc.createTextNode(curve.toString());
-    t.appendChild(text);
-    root.appendChild(t);
 }
 
 /**
@@ -485,21 +462,79 @@ KoColorTransformation* \
                KisPerChannelFilter::createTransformation(const KoColorSp
         dynamic_cast<const KisPerChannelFilterConfiguration*>(config); // Somehow, \
this shouldn't happen  Q_ASSERT(configBC);
 
-    const QVector<QVector<quint16> > &originalTransfers =
-        configBC->transfers();
+    const QVector<QVector<quint16> > &originalTransfers = configBC->transfers();
+    const QList<KisCubicCurve> &originalCurves = configBC->curves();
+
+    /**
+     * TODO: What about the order of channels? (DK)
+     *
+     * Virtual channels are sorted in display order, does Lcms accepts
+     * transforms in display order? Why on Earth it works?! Is it
+     * documented anywhere?
+     */
+    const QVector<VirtualChannelInfo> virtualChannels = getVirtualChannels(cs);
 
-    if (originalTransfers.size() != int(cs->channelCount())) {
-        // We got an illegal number of colorchannels.KisFilter
+    if (originalTransfers.size() != int(virtualChannels.size())) {
+        // We got an illegal number of colorchannels :(
         return 0;
     }
 
+    bool colorsNull = true;
+    bool lightnessNull = true;
+
+    QVector<QVector<quint16> > realTransfers;
+    QVector<quint16> lightnessTansfer;
+    for (int i = 0; i < virtualChannels.size(); i++) {
+        if (virtualChannels[i].type() == VirtualChannelInfo::REAL) {
+            realTransfers << originalTransfers[i];
+            if (colorsNull && !originalCurves[i].isNull()) {
+                colorsNull = false;
+            }
+        } else if (virtualChannels[i].type() == VirtualChannelInfo::LIGHTNESS) {
+            KIS_ASSERT_RECOVER_NOOP(lightnessTansfer.isEmpty());
+            lightnessTansfer = originalTransfers[i];
+
+            if (lightnessNull && !originalCurves[i].isNull()) {
+                lightnessNull = false;
+            }
+        }
+    }
+
     const quint16** transfers = new const quint16*[configBC->curves().size()];
-    for(int i = 0; i < originalTransfers.size(); ++i) {
-        transfers[i] = originalTransfers[i].constData();
+    for(int i = 0; i < realTransfers.size(); ++i) {
+        transfers[i] = realTransfers[i].constData();
     }
-    KoColorTransformation* t = cs->createPerChannelAdjustment(transfers);
+
+    KoColorTransformation *lightnessTransform = 0;
+    KoColorTransformation *colorTransform = 0;
+
+    if (!colorsNull) {
+        colorTransform = cs->createPerChannelAdjustment(transfers);
+    }
+
+    if (!lightnessNull) {
+        lightnessTransform = \
cs->createBrightnessContrastAdjustment(lightnessTansfer.constData()); +    }
+
+    KoColorTransformation *finalTransform = 0;
+
+    if (colorTransform && lightnessTransform) {
+        KoCompositeColorTransformation *compositeTransform =
+            new KoCompositeColorTransformation(
+                KoCompositeColorTransformation::INPLACE);
+
+        compositeTransform->appendTransform(colorTransform);
+        compositeTransform->appendTransform(lightnessTransform);
+
+        finalTransform = compositeTransform;
+    } else if (lightnessTransform) {
+        finalTransform = lightnessTransform;
+    } else  if (colorTransform) {
+        finalTransform = colorTransform;
+    }
+
     delete [] transfers;
-    return t;
+    return finalTransform;
 }
 
 #include "kis_perchannel_filter.moc"
diff --git a/krita/plugins/filters/colorsfilters/kis_perchannel_filter.h \
b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.h index 2aa03a0..6b53075 \
                100644
--- a/krita/plugins/filters/colorsfilters/kis_perchannel_filter.h
+++ b/krita/plugins/filters/colorsfilters/kis_perchannel_filter.h
@@ -30,6 +30,9 @@
 #include <kis_paint_device.h>
 #include "ui_wdg_perchannel.h"
 
+#include "virtual_channel_info.h"
+
+
 class WdgPerChannel : public QWidget, public Ui::WdgPerChannel
 {
     Q_OBJECT
@@ -108,6 +111,10 @@ private Q_SLOTS:
 
 private:
 
+    QVector<VirtualChannelInfo> m_virtualChannels;
+    int m_activeVChannel;
+
+
     // private routines
     inline QPixmap getHistogram();
     inline QPixmap createGradient(Qt::Orientation orient /*, int invert (not used \
now) */); @@ -117,7 +124,6 @@ private:
     KisPaintDeviceSP m_dev;
     KisHistogram *m_histogram;
     mutable QList<KisCubicCurve> m_curves;
-    int m_activeCh;
 
     // scales for displaying color numbers
     double m_scale;
diff --git a/krita/plugins/filters/colorsfilters/virtual_channel_info.cpp \
b/krita/plugins/filters/colorsfilters/virtual_channel_info.cpp new file mode 100644
index 0000000..aae5806
--- /dev/null
+++ b/krita/plugins/filters/colorsfilters/virtual_channel_info.cpp
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "virtual_channel_info.h"
+#include <klocale.h>
+
+
+
+VirtualChannelInfo::VirtualChannelInfo()
+    : m_type(LIGHTNESS),
+      m_pixelIndex(-1),
+      m_realChannelInfo(0)
+{
+}
+
+VirtualChannelInfo::VirtualChannelInfo(Type type,
+                                       int pixelIndex,
+                                       KoChannelInfo *realChannelInfo)
+    : m_type(type),
+      m_pixelIndex(pixelIndex),
+      m_realChannelInfo(realChannelInfo)
+{
+}
+
+VirtualChannelInfo::Type VirtualChannelInfo::type() const {
+    return m_type;
+}
+
+KoChannelInfo* VirtualChannelInfo::channelInfo() const {
+    return m_realChannelInfo;
+}
+
+QString VirtualChannelInfo::name() const {
+    return m_type == REAL ? m_realChannelInfo->name() : i18n("Lightness");
+}
+
+int VirtualChannelInfo::pixelIndex() const {
+    return m_pixelIndex;
+}
+
+KoChannelInfo::enumChannelValueType VirtualChannelInfo::valueType() const {
+    return m_type == REAL ? m_realChannelInfo->channelValueType() : \
KoChannelInfo::FLOAT32; +}
+
+int VirtualChannelInfo::channelSize() const {
+    return m_type == REAL ? m_realChannelInfo->size() : 4;
+}
diff --git a/krita/image/tests/kis_cubic_curve_test.h \
b/krita/plugins/filters/colorsfilters/virtual_channel_info.h similarity index 53%
copy from krita/image/tests/kis_cubic_curve_test.h
copy to krita/plugins/filters/colorsfilters/virtual_channel_info.h
index 60ffaff..9af3ab5 100644
--- a/krita/image/tests/kis_cubic_curve_test.h
+++ b/krita/plugins/filters/colorsfilters/virtual_channel_info.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2010 Cyrille Berger <cberger@cberger.net>
+ *  Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -16,30 +16,34 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#ifndef _KIS_CUBIC_CURVE_TEST_H_
-#define _KIS_CUBIC_CURVE_TEST_H_
+#ifndef __VIRTUAL_CHANNEL_INFO_H
+#define __VIRTUAL_CHANNEL_INFO_H
 
-#include <QtTest>
+#include <KoChannelInfo.h>
 
-#include <QPointF>
-
-class KisCubicCurveTest : public QObject
+class VirtualChannelInfo
 {
-    Q_OBJECT
 public:
-    KisCubicCurveTest();
-private Q_SLOTS:
-
-    void testCreation();
-    void testCopy();
-    void testEdition();
-    void testComparison();
-    void testSerialization();
-    void testValue();
-    void testTransfer();
+    enum Type {
+        REAL,
+        LIGHTNESS
+    };
+
+    VirtualChannelInfo();
+
+    VirtualChannelInfo(Type type, int pixelIndex, KoChannelInfo *realChannelInfo);
+
+    Type type() const;
+    KoChannelInfo* channelInfo() const;
+    QString name() const;
+    int pixelIndex() const;
+    KoChannelInfo::enumChannelValueType valueType() const;
+    int channelSize() const;
+
 private:
-    QPointF pt0, pt1, pt2, pt3, pt4, pt5;
+    Type m_type;
+    int m_pixelIndex;
+    KoChannelInfo *m_realChannelInfo;
 };
 
-
-#endif
+#endif /* __VIRTUAL_CHANNEL_INFO_H */
diff --git a/libs/pigment/CMakeLists.txt b/libs/pigment/CMakeLists.txt
index ae6651b..4f54815 100644
--- a/libs/pigment/CMakeLists.txt
+++ b/libs/pigment/CMakeLists.txt
@@ -52,6 +52,7 @@ set(pigmentcms_SRCS
     KoColorTransformation.cpp
     KoColorTransformationFactory.cpp
     KoColorTransformationFactoryRegistry.cpp
+    KoCompositeColorTransformation.cpp
     KoCompositeOp.cpp
     KoCompositeOpRegistry.cpp
     KoCopyColorConversionTransformation.cpp
diff --git a/libs/pigment/KoCompositeColorTransformation.cpp \
b/libs/pigment/KoCompositeColorTransformation.cpp new file mode 100644
index 0000000..2de2ecf
--- /dev/null
+++ b/libs/pigment/KoCompositeColorTransformation.cpp
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "KoCompositeColorTransformation.h"
+
+#include <QVector>
+
+
+struct KoCompositeColorTransformation::Private
+{
+    ~Private() {
+        qDeleteAll(transformations);
+    }
+
+    QVector<KoColorTransformation*> transformations;
+};
+
+
+KoCompositeColorTransformation::KoCompositeColorTransformation(Mode mode)
+    : m_d(new Private)
+{
+    Q_ASSERT_X(mode == INPLACE, "KoCompositeColorTransformation", "BUFFERED mode is \
not implemented yet!"); +}
+
+KoCompositeColorTransformation::~KoCompositeColorTransformation()
+{
+}
+
+void KoCompositeColorTransformation::appendTransform(KoColorTransformation \
*transform) +{
+    m_d->transformations.append(transform);
+}
+
+void KoCompositeColorTransformation::transform(const quint8 *src, quint8 *dst, \
qint32 nPixels) const +{
+    QVector<KoColorTransformation*>::const_iterator begin = \
m_d->transformations.begin(); +    QVector<KoColorTransformation*>::const_iterator it \
= begin; +    QVector<KoColorTransformation*>::const_iterator end = \
m_d->transformations.end(); +
+    for (; it != end; ++it) {
+        if (it == begin) {
+            (*it)->transform(src, dst, nPixels);
+        } else {
+            (*it)->transform(dst, dst, nPixels);
+        }
+    }
+}
diff --git a/libs/pigment/KoCompositeColorTransformation.h \
b/libs/pigment/KoCompositeColorTransformation.h new file mode 100644
index 0000000..1c4bf28
--- /dev/null
+++ b/libs/pigment/KoCompositeColorTransformation.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KO_COMPOSITE_COLOR_TRANSFORMATION_H
+#define __KO_COMPOSITE_COLOR_TRANSFORMATION_H
+
+#include "KoColorTransformation.h"
+
+#include <QScopedPointer>
+
+
+class PIGMENTCMS_EXPORT KoCompositeColorTransformation : public \
KoColorTransformation +{
+public:
+    enum Mode {
+        INPLACE = 0, /// transform pixels in place (in 'dst' buffer)
+        BUFFERED /// transform using a temporary buffer (not implemented yet)
+    };
+
+public:
+    KoCompositeColorTransformation(Mode mode);
+    ~KoCompositeColorTransformation();
+
+    void appendTransform(KoColorTransformation *transform);
+
+    void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const;
+
+private:
+    struct Private;
+    const QScopedPointer<Private> m_d;
+};
+
+#endif /* __KO_COMPOSITE_COLOR_TRANSFORMATION_H */


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

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