Commit c6ec8991 authored by Halla Rempt's avatar Halla Rempt

...

parent 31c9a0fe
......@@ -103,7 +103,7 @@ public:
{
//if (m_model="RGBA" || m_colorize) {
/*It'd be nice to have LCH automatically selector for LAB in the future, but I don't know how to select LAB
/*It'd be nice to have LCH automatically selector for LAB in the future, but I don't know how to select LAB
* */
const RGBPixel* src = reinterpret_cast<const RGBPixel*>(srcU8);
RGBPixel* dst = reinterpret_cast<RGBPixel*>(dstU8);
......@@ -191,7 +191,7 @@ public:
sat *= (m_adj_s + 1.0);
//sat = qBound(0.0, sat, 1.0);
intensity += (m_adj_v);
HCIToRGB(hue/360.0, sat, intensity, &red, &green, &blue);
......@@ -223,7 +223,7 @@ public:
r = red;
g = green;
b = blue;
} else if (m_type == 4) {
qreal red = SCALE_TO_FLOAT(src->red);
......@@ -267,7 +267,7 @@ public:
qreal a = SCALE_TO_FLOAT(src->a);
qreal b = SCALE_TO_FLOAT(src->b);
qreal L, C, H;
while (nPixels > 0) {
if (m_type = 4) {
a *= (m_adj_h + 1.0);
......@@ -333,7 +333,7 @@ public:
}
return -1;
}
/**
* name - "h", "s" or "v"
* (h)ue in range <-1.0, 1.0> ( for user, show as -180, 180 or 0, 360 for colorize)
......@@ -392,6 +392,16 @@ class KisHSVCurveAdjustment : public KoColorTransformation
typedef typename RGBTrait::Pixel RGBPixel;
public:
enum enumChannel {
chRed = 0,
chGreen = 1,
chBlue = 2,
chHue = 3,
chSaturation = 4,
chValue = 5,
chChannelCount
};
KisHSVCurveAdjustment() :
m_lumaRed(0.0),
m_lumaGreen(0.0),
......@@ -401,7 +411,7 @@ public:
QList<QString> parameters() const override
{
QList<QString> list;
list << "curve" << "channel" << "lumaRed" << "lumaGreen"<< "lumaBlue";
list << "curve" << "channel" << "driverChannel" << "relative" << "lumaRed" << "lumaGreen"<< "lumaBlue";
return list;
}
......@@ -411,6 +421,10 @@ public:
return PAR_CURVE;
} else if (name == "channel") {
return PAR_CHANNEL;
} else if (name == "driverChannel") {
return PAR_DRIVER_CHANNEL;
} else if (name == "relative") {
return PAR_RELATIVE;
} else if (name == "lumaRed") {
return PAR_LUMA_R;
} else if (name == "lumaGreen") {
......@@ -434,11 +448,25 @@ public:
case PAR_CURVE:
m_curve = parameter.value<QVector<quint16>>();
break;
case PAR_CHANNEL: {
case PAR_CHANNEL:
case PAR_DRIVER_CHANNEL: {
int channel = parameter.toInt();
KIS_ASSERT_RECOVER_RETURN(0 <= channel && channel < 3 && "Channel must be 0, 1 or 2. Ignored!");
m_channel = channel;
if (!(0 <= channel && channel < chChannelCount)) {
qDebug() << "Invalid channel!!! " << channel;
return;
}
//KIS_ASSERT_RECOVER_RETURN(0 <= channel && channel < chChannelCount && "Invalid channel. Ignored!");
if (id == PAR_CHANNEL) {
m_channel = channel;
} else {
m_driverChannel = channel;
}
} break;
case PAR_RELATIVE:
m_relative = parameter.toBool();
break;
case PAR_LUMA_R:
m_lumaRed = parameter.toDouble();
break;
......@@ -457,30 +485,46 @@ public:
{
const RGBPixel* src = reinterpret_cast<const RGBPixel*>(srcU8);
RGBPixel* dst = reinterpret_cast<RGBPixel*>(dstU8);
float r = 0.0;
float g = 0.0;
float b = 0.0;
float max = m_curve.size() - 1;
float component[3];
float &hue = component[0];
float component[chChannelCount];
float &h = component[chHue];
float &s = component[chSaturation];
float &v = component[chValue];
float &r = component[chRed];
float &g = component[chGreen];
float &b = component[chBlue];
int driverChannel = m_relative ? m_driverChannel : m_channel;
while (nPixels > 0) {
component[chRed] = src->red;
component[chGreen] = src->green;
component[chBlue] = src->blue;
RGBToHSV(
SCALE_TO_FLOAT(src->red), SCALE_TO_FLOAT(src->green), SCALE_TO_FLOAT(src->blue),
&component[0], &component[1], &component[2]
&h, &s, &v
);
// Normalize hue to 0.0 to 1.0 range
hue /= 360.0f;
h /= 360.0f;
component[m_channel] = lookupComponent(component[m_channel], max);
float adjustment = lookupComponent(component[driverChannel], max);
if (m_relative) {
component[m_channel] += adjustment - 0.5f; // fixme: ducttape
} else {
component[m_channel] = adjustment;
}
hue *= 360.0f;
if (hue > 360) hue -= 360;
if (hue < 0) hue += 360;
h *= 360.0f;
HSVToRGB(component[0], component[1], component[2], &r, &g, &b);
if (h > 360) h -= 360;
if (h < 0) h += 360;
if (m_channel > chBlue) {
HSVToRGB(h, s, v, &r, &g, &b);
}
clamp< _channel_type_ >(&r, &g, &b);
dst->red = SCALE_FROM_FLOAT(r);
......@@ -499,6 +543,7 @@ public:
{
// No curve for this component? Pass through modified
if (max < 2) return x;
if (x < 0) return m_curve[0];
float lookup = x * max;
float base = floor(lookup);
......@@ -516,17 +561,21 @@ public:
private:
enum ParameterID
enum enumParameterID
{
PAR_CURVE,
PAR_CHANNEL,
PAR_DRIVER_CHANNEL,
PAR_RELATIVE,
PAR_LUMA_R,
PAR_LUMA_G,
PAR_LUMA_B,
};
QVector<quint16> m_curve;
int m_channel;
int m_channel = 0;
int m_driverChannel = 0;
bool m_relative = false;
/* Note: the filter currently only supports HSV, so these are
* unused, but will be needed once HSL, etc.
......
......@@ -2,7 +2,9 @@ set(kritacolorsfilters_SOURCES
colorsfilters.cpp
kis_hsv_adjustment_filter.cpp
virtual_channel_info.cpp
kis_multichannel_filter_base.cpp
kis_perchannel_filter.cpp
kis_cross_channel_filter.cpp
kis_color_balance_filter.cpp
kis_desaturate_filter.cpp
)
......
......@@ -58,6 +58,7 @@
#include "kis_hsv_adjustment_filter.h"
#include "kis_perchannel_filter.h"
#include "kis_cross_channel_filter.h"
#include "kis_color_balance_filter.h"
#include "kis_desaturate_filter.h"
......@@ -69,6 +70,7 @@ ColorsFilters::ColorsFilters(QObject *parent, const QVariantList &)
KisFilterRegistry * manager = KisFilterRegistry::instance();
manager->add(new KisAutoContrast());
manager->add(new KisPerChannelFilter());
manager->add(new KisCrossChannelFilter());
manager->add(new KisDesaturateFilter());
manager->add(new KisHSVAdjustmentFilter());
manager->add(new KisColorBalanceFilter());
......
/*
* This file is part of Krita
*
* Copyright (c) 2018 Jouni Pentikainen <joupent@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_cross_channel_filter.h"
#include <Qt>
#include <QLayout>
#include <QPixmap>
#include <QPainter>
#include <QLabel>
#include <QComboBox>
#include <QDomDocument>
#include <QHBoxLayout>
#include "KoChannelInfo.h"
#include "KoBasicHistogramProducers.h"
#include "KoColorModelStandardIds.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>
#include <kis_selection.h>
#include <kis_paint_device.h>
#include <kis_processing_information.h>
#include "kis_histogram.h"
#include "kis_painter.h"
#include "widgets/kis_curve_widget.h"
// KisCrossChannelFilterConfiguration
KisCrossChannelFilterConfiguration::KisCrossChannelFilterConfiguration(int channelCount)
: KisMultiChannelFilterConfigurationBase(channelCount, "crosschannel", 1)
{
m_driverChannels.resize(channelCount);
}
KisCrossChannelFilterConfiguration::~KisCrossChannelFilterConfiguration()
{}
const QVector<int> KisCrossChannelFilterConfiguration::driverChannels() const
{
return m_driverChannels;
}
void KisCrossChannelFilterConfiguration::setDriverChannels(QVector<int> driverChannels)
{
m_driverChannels = driverChannels;
}
void KisCrossChannelFilterConfiguration::fromXML(const QDomElement& root)
{
KisMultiChannelFilterConfigurationBase::fromXML(root);
// TODO
}
void KisCrossChannelFilterConfiguration::toXML(QDomDocument& doc, QDomElement& root) const
{
KisMultiChannelFilterConfigurationBase::toXML(doc, root);
// TODO
}
KisCrossChannelConfigWidget::KisCrossChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f)
: KisMultiChannelConfigWidgetBase(parent, dev, f)
{
const int virtualChannelCount = m_virtualChannels.size();
m_driverChannels.resize(virtualChannelCount);
KisMultiChannelFilterConfigurationBase::initDefaultCurves(m_curves, virtualChannelCount);
init();
for (int i = 0; i < virtualChannelCount; i++) {
const VirtualChannelInfo &info = m_virtualChannels[i];
m_page->cmbDriverChannel->addItem(info.name(), info.pixelIndex());
}
connect(m_page->cmbDriverChannel, SIGNAL(activated(int)), this, SLOT(slotSetDriverChannel(int)));
}
// KisCrossChannelConfigWidget
KisCrossChannelConfigWidget::~KisCrossChannelConfigWidget()
{}
void KisCrossChannelConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config)
{
// TODO
}
KisPropertiesConfigurationSP KisCrossChannelConfigWidget::configuration() const
{
KisPropertiesConfigurationSP cfgSP = new KisCrossChannelFilterConfiguration(m_virtualChannels.count());
auto *cfg = static_cast<KisCrossChannelFilterConfiguration*>(cfgSP.data());
m_curves[m_activeVChannel] = m_page->curveWidget->curve();
cfg->setCurves(m_curves);
cfg->setDriverChannels(m_driverChannels);
return cfgSP;
}
void KisCrossChannelConfigWidget::updateChannelRange()
{
float m_shift = 0;
float m_scale = 100.0;
int min = 0;
int max = 100;
m_page->curveWidget->setupInOutControls(m_page->intIn, m_page->intOut, min, max);
}
void KisCrossChannelConfigWidget::slotSetDriverChannel(int channel)
{
m_driverChannels[m_activeVChannel] = channel;
updateChannelRange();
// TODO: update histogram?
}
// KisCrossChannelFilter
KisCrossChannelFilter::KisCrossChannelFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Cross-channel adjustment curves..."))
{
//setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
setSupportsPainting(true);
setColorSpaceIndependence(TO_LAB16);
}
KisCrossChannelFilter::~KisCrossChannelFilter()
{}
KisConfigWidget * KisCrossChannelFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const
{
return new KisCrossChannelConfigWidget(parent, dev);
}
KisFilterConfigurationSP KisCrossChannelFilter::factoryConfiguration() const
{
return new KisCrossChannelFilterConfiguration(0);
}
int mapChannel(const VirtualChannelInfo &channel) {
// See KisHSVCurveAdjustment::enumChannel
switch (channel.type()) {
case VirtualChannelInfo::HUE:
return 3;
case VirtualChannelInfo::SATURATION:
return 4;
case VirtualChannelInfo::LIGHTNESS:
return 5;
default:
// TODO
return qBound(0, channel.pixelIndex(), 2);
};
}
KoColorTransformation* KisCrossChannelFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const // TODO
{
const KisCrossChannelFilterConfiguration* configBC =
dynamic_cast<const KisCrossChannelFilterConfiguration*>(config.data());
Q_ASSERT(configBC);
const QVector<QVector<quint16> > &originalTransfers = configBC->transfers();
const QList<KisCubicCurve> &curves = configBC->curves();
const QVector<int> &drivers = configBC->driverChannels();
const QVector<VirtualChannelInfo> virtualChannels =
KisMultiChannelFilterConfigurationBase::getVirtualChannels(cs);
if (originalTransfers.size() != int(virtualChannels.size())) {
// We got an illegal number of colorchannels :(
return 0;
}
QVector<KoColorTransformation*> transforms;
// for (int i = 0; i < virtualChannels.size(); i++) {
for (int i = virtualChannels.size() - 1; i >= 0; i--) {
if (!curves[i].isNull()) {
int channel = mapChannel(virtualChannels[i]);
int driverChannel = mapChannel(virtualChannels[drivers[i]]);
QHash<QString, QVariant> params;
params["channel"] = channel;
params["driverChannel"] = driverChannel; // FIXME: channel number mismatch
params["curve"] = QVariant::fromValue(originalTransfers[i]);
params["relative"] = true;
params["lumaRed"] = cs->lumaCoefficients()[0];
params["lumaGreen"] = cs->lumaCoefficients()[1];
params["lumaBlue"] = cs->lumaCoefficients()[2];
transforms << cs->createColorTransformation("hsv_curve_adjustment", params);
}
}
return KoCompositeColorTransformation::createOptimizedCompositeTransform(transforms);
}
bool KisCrossChannelFilter::needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const
{
Q_UNUSED(config);
return cs->colorModelId() == AlphaColorModelID;
}
/*
* This file is part of Krita
*
* Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
*
* 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_CROSSCHANNEL_FILTER_H_
#define _KIS_CROSSCHANNEL_FILTER_H_
#include <QPair>
#include <QList>
#include <filter/kis_color_transformation_filter.h>
#include <filter/kis_color_transformation_configuration.h>
#include <kis_config_widget.h>
#include <kis_paint_device.h>
#include "ui_wdg_perchannel.h"
#include "virtual_channel_info.h"
#include "kis_multichannel_filter_base.h"
/**
*
*/
class KisCrossChannelFilter
: public KisColorTransformationFilter
{
public:
KisCrossChannelFilter();
~KisCrossChannelFilter() override;
KisConfigWidget * createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const override;
KisFilterConfigurationSP factoryConfiguration() const override;
KoColorTransformation* createTransformation(const KoColorSpace *cs, const KisFilterConfigurationSP config) const override;
bool needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const override;
static inline KoID id() {
return KoID("crosschannel", i18n("Cross-channel color Adjustment"));
}
private:
};
class KisCrossChannelFilterConfiguration : public KisMultiChannelFilterConfigurationBase
{
public:
KisCrossChannelFilterConfiguration(int n);
~KisCrossChannelFilterConfiguration() override;
static inline void initDefaultCurves(QList<KisCubicCurve> &curves, int nCh);
const QVector<int> driverChannels() const;
void setDriverChannels(QVector<int> driverChannels);
using KisFilterConfiguration::fromXML;
using KisFilterConfiguration::toXML;
void fromXML(const QDomElement& e) override;
void toXML(QDomDocument& doc, QDomElement& root) const override;
private:
QVector<int> m_driverChannels;
};
/*
class WdgCrossChannel : public QWidget, public Ui::WdgCrossChannel
{
Q_OBJECT
public:
WdgCrossChannel(QWidget *parent) : QWidget(parent) {
setupUi(this);
}
};
*/
class KisCrossChannelConfigWidget : public KisMultiChannelConfigWidgetBase
{
Q_OBJECT
public:
KisCrossChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f = 0);
~KisCrossChannelConfigWidget() override;
void setConfiguration(const KisPropertiesConfigurationSP config) override;
KisPropertiesConfigurationSP configuration() const override;
protected:
void updateChannelRange() override;
private Q_SLOTS:
void slotSetDriverChannel(int channel);
private:
QVector<int> m_driverChannels;
};
#endif
/*
* This file is part of Krita
*
* Copyright (c) 2005 C. Boemann <cbo@boemann.dk>
*
* 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_perchannel_filter.h"
#include <Qt>
#include <QLayout>
#include <QPixmap>
#include <QPainter>
#include <QLabel>
#include <QComboBox>
#include <QDomDocument>
#include <QHBoxLayout>