[krita/krita/3.3] plugins/filters: [Feature] ASC-CDL color balance filter(Slope, Offset, Power)

Boudewijn Rempt null at kde.org
Sat Oct 14 08:59:36 UTC 2017


Git commit 3f81a96dc7d5b95ba4cc3c9b1eb647fb630a92dd by Boudewijn Rempt, on behalf of Wolthera van Hövell tot Westerflier.
Committed on 14/10/2017 at 08:39.
Pushed by rempt into branch 'krita/3.3'.

[Feature] ASC-CDL color balance filter(Slope, Offset, Power)

This is a simple color balance filter as decided by the American
Society of Cinematographers. It's purpose is to make communicating color
balance easier over different applications.

It is also interesting in that it is so simple it does not clip high-bit depth
values.

There's still some issues with the filter, but they are mostly GUI issues,
so I am pushing this to prevent bitrot. I have noted the possible list of
improvements in the header of the widget class.

BUG:355747
Differential revision: https://phabricator.kde.org/D8184
CCMAIL:kimageshop at kde.org

M  +1    -0    plugins/filters/CMakeLists.txt
A  +11   -0    plugins/filters/asccdl/CMakeLists.txt
A  +127  -0    plugins/filters/asccdl/kis_asccdl_filter.cpp     [License: GPL (v2+)]
A  +61   -0    plugins/filters/asccdl/kis_asccdl_filter.h     [License: GPL (v2+)]
A  +103  -0    plugins/filters/asccdl/kis_wdg_asccdl.cpp     [License: GPL (v2+)]
A  +62   -0    plugins/filters/asccdl/kis_wdg_asccdl.h     [License: GPL (v2+)]
A  +9    -0    plugins/filters/asccdl/kritaasccdl.json
A  +105  -0    plugins/filters/asccdl/wdg_asccdl.ui

https://commits.kde.org/krita/3f81a96dc7d5b95ba4cc3c9b1eb647fb630a92dd

diff --git a/plugins/filters/CMakeLists.txt b/plugins/filters/CMakeLists.txt
index 8454461ca98..6faf7d54aba 100644
--- a/plugins/filters/CMakeLists.txt
+++ b/plugins/filters/CMakeLists.txt
@@ -26,3 +26,4 @@ add_subdirectory( normalize )
 add_subdirectory( gradientmap )
 add_subdirectory( threshold )
 add_subdirectory( halftone )
+add_subdirectory( asccdl )
diff --git a/plugins/filters/asccdl/CMakeLists.txt b/plugins/filters/asccdl/CMakeLists.txt
new file mode 100644
index 00000000000..94a0aaeaa23
--- /dev/null
+++ b/plugins/filters/asccdl/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(kritaasccdl_SOURCES
+    kis_asccdl_filter.cpp
+    kis_wdg_asccdl.cpp
+)
+
+ki18n_wrap_ui(kritaasccdl_SOURCES
+    wdg_asccdl.ui
+    )
+add_library(kritaasccdl MODULE ${kritaasccdl_SOURCES})
+target_link_libraries(kritaasccdl kritaui)
+install(TARGETS kritaasccdl  DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
diff --git a/plugins/filters/asccdl/kis_asccdl_filter.cpp b/plugins/filters/asccdl/kis_asccdl_filter.cpp
new file mode 100644
index 00000000000..08df10514cc
--- /dev/null
+++ b/plugins/filters/asccdl/kis_asccdl_filter.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017 Wolthera van Hövell tot Westerflier <griffinvalley at 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 "kis_asccdl_filter.h"
+#include "kis_wdg_asccdl.h"
+#include <kpluginfactory.h>
+#include <klocalizedstring.h>
+#include <filter/kis_filter_registry.h>
+#include <filter/kis_color_transformation_configuration.h>
+#include <qmath.h>
+
+K_PLUGIN_FACTORY_WITH_JSON(KritaASCCDLFactory,
+                           "kritaasccdl.json",
+                           registerPlugin<KritaASCCDL>();)
+
+
+KritaASCCDL::KritaASCCDL(QObject *parent, const QVariantList &) : QObject(parent)
+{
+    KisFilterRegistry::instance()->add(KisFilterSP(new KisFilterASCCDL()));
+}
+
+KritaASCCDL::~KritaASCCDL()
+{
+
+}
+
+KisFilterASCCDL::KisFilterASCCDL(): KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Slope, Offset, Power.."))
+{
+    setSupportsPainting(true);
+    setSupportsAdjustmentLayers(true);
+    setSupportsLevelOfDetail(true);
+    setSupportsThreading(true);
+    setColorSpaceIndependence(FULLY_INDEPENDENT);
+    setShowConfigurationWidget(true);
+}
+
+KoColorTransformation *KisFilterASCCDL::createTransformation(const KoColorSpace *cs,
+                                                             const KisFilterConfigurationSP config) const
+{
+    KoColor black(Qt::black, cs);
+    return new KisASCCDLTransformation(cs,
+                                       config->getColor("slope", black),
+                                       config->getColor("offset", black),
+                                       config->getColor("power", black));
+}
+
+KisConfigWidget *KisFilterASCCDL::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const
+{
+    return new KisASCCDLConfigWidget(parent, dev->colorSpace());
+}
+
+bool KisFilterASCCDL::needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const
+{
+    KoColor black(Qt::black, cs);
+    KoColor offset = config->getColor("offset", black);
+    offset.convertTo(cs);
+    if (cs->difference(black.data(), offset.data())>0) {
+        return true;
+    }
+    return false;
+}
+
+KisFilterConfigurationSP KisFilterASCCDL::factoryConfiguration() const
+{
+    KisColorTransformationConfigurationSP config = new KisColorTransformationConfiguration(id().id(), 0);
+    QVariant colorVariant("KoColor");
+    KoColor black;
+    black.fromQColor(QColor(Qt::black));
+    KoColor white;
+    white.fromQColor(QColor(Qt::white));
+    colorVariant.setValue(white);
+    config->setProperty( "slope", colorVariant);
+    config->setProperty( "power", colorVariant);
+    colorVariant.setValue(black);
+    config->setProperty("offset", colorVariant);
+    return config;
+}
+
+KisASCCDLTransformation::KisASCCDLTransformation(const KoColorSpace *cs, KoColor slope, KoColor offset, KoColor power)
+{
+    QVector<float> slopeN(cs->channelCount());
+    slope.convertTo(cs);
+    slope.colorSpace()->normalisedChannelsValue(slope.data(), slopeN);
+    m_slope = slopeN;
+    offset.convertTo(cs);
+    QVector<float> offsetN(cs->channelCount());
+    offset.colorSpace()->normalisedChannelsValue(offset.data(), offsetN);
+    m_offset = offsetN;
+    power.convertTo(cs);
+    QVector<float> powerN(cs->channelCount());
+    power.colorSpace()->normalisedChannelsValue(power.data(), powerN);
+    m_power = powerN;
+    m_cs = cs;
+}
+
+void KisASCCDLTransformation::transform(const quint8 *src, quint8 *dst, qint32 nPixels) const
+{
+    QVector<float> normalised(m_cs->channelCount());
+    const int pixelSize = m_cs->pixelSize();
+    while (nPixels--) {
+        m_cs->normalisedChannelsValue(src, normalised);
+
+        for (int c=0; c<m_cs->channelCount(); c++){
+            normalised[c] = qPow( (normalised.at(c)*m_slope.at(c))+m_offset.at(c), m_power.at(c));
+        }
+        m_cs->fromNormalisedChannelsValue(dst, normalised);
+        src += pixelSize;
+        dst += pixelSize;
+    }
+}
+
+#include "kis_asccdl_filter.moc"
diff --git a/plugins/filters/asccdl/kis_asccdl_filter.h b/plugins/filters/asccdl/kis_asccdl_filter.h
new file mode 100644
index 00000000000..50c38efecc0
--- /dev/null
+++ b/plugins/filters/asccdl/kis_asccdl_filter.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017 Wolthera van Hövell tot Westerflier <griffinvalley at 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 KIS_ASCCDL_FILTER_H
+#define KIS_ASCCDL_FILTER_H
+
+#include <filter/kis_filter.h>
+#include "filter/kis_color_transformation_filter.h"
+
+class KritaASCCDL : public QObject
+{
+    Q_OBJECT
+public:
+    KritaASCCDL(QObject *parent, const QVariantList &);
+    ~KritaASCCDL() override;
+};
+
+class KisFilterASCCDL: public KisColorTransformationFilter
+{
+public:
+    KisFilterASCCDL();
+public:
+
+    static inline KoID id() {
+        return KoID("asc-cdl", i18n("Slope, Offset, Power(ASC-CDL)"));
+    }
+    KoColorTransformation *createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const override;
+    KisConfigWidget *createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const override;
+    bool needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const;
+protected:
+    KisFilterConfigurationSP factoryConfiguration() const override;
+};
+
+class KisASCCDLTransformation : public KoColorTransformation
+{
+public:
+    KisASCCDLTransformation(const KoColorSpace *cs, KoColor slope, KoColor offset, KoColor power);
+    void transform(const quint8* src, quint8* dst, qint32 nPixels) const override;
+private:
+    QVector<float> m_slope;
+    QVector<float> m_offset;
+    QVector<float> m_power;
+    const KoColorSpace *m_cs;
+};
+
+#endif // KIS_ASCCDL_H
diff --git a/plugins/filters/asccdl/kis_wdg_asccdl.cpp b/plugins/filters/asccdl/kis_wdg_asccdl.cpp
new file mode 100644
index 00000000000..afce1f6b334
--- /dev/null
+++ b/plugins/filters/asccdl/kis_wdg_asccdl.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017 Wolthera van Hövell tot Westerflier <griffinvalley at 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 "kis_wdg_asccdl.h"
+#include <kis_config.h>
+#include <kis_color_button.h>
+#include <kis_filter_configuration.h>
+#include <KisVisualColorSelectorShape.h>
+#include <KisVisualRectangleSelectorShape.h>
+#include <KisVisualEllipticalSelectorShape.h>
+
+KisASCCDLConfigWidget::KisASCCDLConfigWidget(QWidget *parent, const KoColorSpace *cs)
+    :KisConfigWidget(parent),
+    m_page(new Ui_WdgASCCDL),
+    m_cs(cs)
+
+{
+    KoColor black(Qt::black, cs);
+    m_page->setupUi(this);
+    m_page->btnSlope->setColor(black);
+    m_page->btnOffset->setColor(black);
+    m_page->btnPower->setColor(black);
+
+    connect(m_page->btnSlope , SIGNAL(changed(const KoColor)), this,  SLOT(slopeColorChanged(const KoColor)));
+    connect(m_page->btnOffset, SIGNAL(changed(const KoColor)), this,  SLOT(offsetColorChanged(const KoColor)));
+    connect(m_page->btnPower , SIGNAL(changed(const KoColor)), this,  SLOT(powerColorChanged(const KoColor)));
+    connect(m_page->slopeSelector, SIGNAL(sigNewColor(const KoColor)), this, SLOT(slopeColorChanged(const KoColor)));
+    connect(m_page->offsetSelector, SIGNAL(sigNewColor(const KoColor)), this, SLOT(offsetColorChanged(const KoColor)));
+    connect(m_page->powerSelector, SIGNAL(sigNewColor(const KoColor)), this, SLOT(powerColorChanged(const KoColor)));
+}
+
+KisASCCDLConfigWidget::~KisASCCDLConfigWidget()
+{
+    delete m_page;
+}
+
+KisPropertiesConfigurationSP KisASCCDLConfigWidget::configuration() const
+{
+    KisFilterConfigurationSP config = new KisFilterConfiguration("asc-cdl", 0);
+    QVariant colorVariant("KoColor");
+    colorVariant.setValue(m_page->btnSlope->color());
+    config->setProperty("slope", colorVariant);
+    colorVariant.setValue(m_page->btnOffset->color());
+    config->setProperty("offset", colorVariant);
+    colorVariant.setValue(m_page->btnPower->color());
+    config->setProperty("power", colorVariant);
+    return config;
+}
+
+void KisASCCDLConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config)
+{
+    m_page->btnSlope->setColor (config->getColor( "slope", KoColor(Qt::white, m_cs)));
+    m_page->slopeSelector->slotSetColor(config->getColor("slope", KoColor(Qt::white, m_cs)));
+    m_page->btnOffset->setColor(config->getColor("offset", KoColor(Qt::black, m_cs)));
+    m_page->offsetSelector->slotSetColor(config->getColor("offset", KoColor(Qt::white, m_cs)));
+    m_page->btnPower->setColor (config->getColor( "power", KoColor(Qt::white, m_cs)));
+    m_page->powerSelector->slotSetColor(config->getColor("power", KoColor(Qt::white, m_cs)));
+}
+
+void KisASCCDLConfigWidget::slopeColorChanged(const KoColor &c)
+{
+    if (QObject::sender() == m_page->btnSlope) {
+        m_page->slopeSelector->slotSetColor(c);
+    } else {
+        m_page->btnSlope->setColor(c);
+    }
+    emit sigConfigurationItemChanged();
+}
+
+void KisASCCDLConfigWidget::offsetColorChanged(const KoColor &c)
+{
+    if (QObject::sender() == m_page->btnOffset) {
+        m_page->offsetSelector->slotSetColor(c);
+    } else {
+        m_page->btnOffset->setColor(c);
+    }
+    emit sigConfigurationItemChanged();
+}
+
+void KisASCCDLConfigWidget::powerColorChanged(const KoColor &c)
+{
+    if (QObject::sender() == m_page->btnPower) {
+        m_page->powerSelector->slotSetColor(c);
+    } else {
+        m_page->btnPower->setColor(c);
+    }
+    emit sigConfigurationItemChanged();
+}
diff --git a/plugins/filters/asccdl/kis_wdg_asccdl.h b/plugins/filters/asccdl/kis_wdg_asccdl.h
new file mode 100644
index 00000000000..bdca6461020
--- /dev/null
+++ b/plugins/filters/asccdl/kis_wdg_asccdl.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017 Wolthera van Hövell tot Westerflier <griffinvalley at 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 KIS_WDG_ASCCDL_H
+#define KIS_WDG_ASCCDL_H
+#include <kis_config_widget.h>
+#include <QWidget>
+#include "ui_wdg_asccdl.h"
+#include <KisVisualRectangleSelectorShape.h>
+#include <KisVisualEllipticalSelectorShape.h>
+
+class Ui_WdgASCCDL;
+
+/**
+ * @brief The KisASCCDLConfigWidget class
+ * this handles the configuration widget for the slope offset power filter.
+ *
+ * Future improvements:
+ * 1. Have the cs that the widgets gets when being created be actually the image cs.
+ * 2. Have the shape be force to a HSV wheel with a slider.
+ * 3. Make it easier to select power higher than 1.0 (it is possible, but cumbersome)
+ * 4. make it easier to access ocio from filters.
+ * 5. Implement saturation whenever we can figure out what the formula is for that.
+ * 6. Implement a way to retrieve and store xml data according to the asc-cdl spec...
+ *
+ * The main problem for 5 and 6 is that I am unable to find the actual asc-cdl spec.
+ */
+
+class KisASCCDLConfigWidget : public KisConfigWidget
+{
+
+    Q_OBJECT
+
+public:
+    KisASCCDLConfigWidget(QWidget * parent, const KoColorSpace *cs);
+    ~KisASCCDLConfigWidget() override;
+
+    KisPropertiesConfigurationSP  configuration() const override;
+    void setConfiguration(const KisPropertiesConfigurationSP config) override;
+    Ui_WdgASCCDL *m_page;
+    const KoColorSpace *m_cs;
+public Q_SLOTS:
+    void slopeColorChanged(const KoColor &c);
+    void offsetColorChanged(const KoColor &c);
+    void powerColorChanged(const KoColor &c);
+};
+
+#endif //KIS_WDG_ASCCDL_H
diff --git a/plugins/filters/asccdl/kritaasccdl.json b/plugins/filters/asccdl/kritaasccdl.json
new file mode 100644
index 00000000000..5e09c37b7ee
--- /dev/null
+++ b/plugins/filters/asccdl/kritaasccdl.json
@@ -0,0 +1,9 @@
+{
+    "Id": "ASC CDL Color Balance",
+    "Type": "Service",
+    "X-KDE-Library": "kritaasccdl",
+    "X-KDE-ServiceTypes": [
+        "Krita/Filter"
+    ],
+    "X-Krita-Version": "40"
+}
diff --git a/plugins/filters/asccdl/wdg_asccdl.ui b/plugins/filters/asccdl/wdg_asccdl.ui
new file mode 100644
index 00000000000..be3f17056dd
--- /dev/null
+++ b/plugins/filters/asccdl/wdg_asccdl.ui
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>WdgASCCDL</class>
+ <widget class="QWidget" name="WdgASCCDL">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string/>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="3" column="0">
+    <widget class="KisColorButton" name="btnSlope">
+     <property name="text">
+      <string>PushButton</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="2">
+    <widget class="KisColorButton" name="btnPower">
+     <property name="text">
+      <string>PushButton</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="QLabel" name="lblOffset">
+     <property name="text">
+      <string>Offset:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="0" colspan="2">
+    <widget class="QLabel" name="lblBase">
+     <property name="text">
+      <string>ASC-CDL  color balance</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1">
+    <widget class="KisColorButton" name="btnOffset">
+     <property name="text">
+      <string>PushButton</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="2">
+    <widget class="QLabel" name="lblPower">
+     <property name="text">
+      <string>Power:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="lblSlope">
+     <property name="text">
+      <string>Slope:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="KisVisualColorSelector" name="slopeSelector" native="true"/>
+   </item>
+   <item row="2" column="1">
+    <widget class="KisVisualColorSelector" name="offsetSelector" native="true"/>
+   </item>
+   <item row="2" column="2">
+    <widget class="KisVisualColorSelector" name="powerSelector" native="true"/>
+   </item>
+   <item row="4" column="0" colspan="3">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>KisColorButton</class>
+   <extends>QPushButton</extends>
+   <header>kis_color_button.h</header>
+  </customwidget>
+  <customwidget>
+   <class>KisVisualColorSelector</class>
+   <extends>QWidget</extends>
+   <header>KisVisualColorSelector.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>



More information about the kimageshop mailing list