[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