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

Wolthera van Hövell tot Westerflier null at kde.org
Wed Oct 11 13:35:22 UTC 2017


Git commit b3f9a490011abb5c7c717789ba68c55f89897db8 by Wolthera van Hövell tot Westerflier.
Committed on 11/10/2017 at 13:35.
Pushed by woltherav into branch 'master'.

[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/b3f9a490011abb5c7c717789ba68c55f89897db8

diff --git a/plugins/filters/CMakeLists.txt b/plugins/filters/CMakeLists.txt
index b6896a8961f..8f16508e751 100644
--- a/plugins/filters/CMakeLists.txt
+++ b/plugins/filters/CMakeLists.txt
@@ -28,3 +28,4 @@ add_subdirectory( threshold )
 add_subdirectory( halftone )
 add_subdirectory( edgedetection )
 add_subdirectory( convertheightnormalmap )
+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