diff --git a/plugins/color/colorspaceextensions/kis_hsv_adjustment.cpp b/plugins/color/colorspaceextensions/kis_hsv_adjustment.cpp index fb1835fdf5..b8f2e89b26 100644 --- a/plugins/color/colorspaceextensions/kis_hsv_adjustment.cpp +++ b/plugins/color/colorspaceextensions/kis_hsv_adjustment.cpp @@ -1,671 +1,622 @@ /* * Copyright (c) 2007 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2 * of the License. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_hsv_adjustment.h" #include #ifdef HAVE_OPENEXR #include #endif #include #include #include #include #include #include #include #include #include #define SCALE_TO_FLOAT( v ) KoColorSpaceMaths< _channel_type_, float>::scaleToA( v ) #define SCALE_FROM_FLOAT( v ) KoColorSpaceMaths< float, _channel_type_>::scaleToA( v ) template void clamp(float* r, float* g, float* b); #define FLOAT_CLAMP( v ) *v = (*v < 0.0) ? 0.0 : ( (*v>1.0) ? 1.0 : *v ) template<> void clamp(float* r, float* g, float* b) { FLOAT_CLAMP(r); FLOAT_CLAMP(g); FLOAT_CLAMP(b); } template<> void clamp(float* r, float* g, float* b) { FLOAT_CLAMP(r); FLOAT_CLAMP(g); FLOAT_CLAMP(b); } #ifdef HAVE_OPENEXR template<> void clamp(float* r, float* g, float* b) { Q_UNUSED(r); Q_UNUSED(g); Q_UNUSED(b); } #endif template<> void clamp(float* r, float* g, float* b) { Q_UNUSED(r); Q_UNUSED(g); Q_UNUSED(b); } template class KisHSVAdjustment : public KoColorTransformation { typedef traits RGBTrait; typedef typename RGBTrait::Pixel RGBPixel; public: KisHSVAdjustment() : m_adj_h(0.0), m_adj_s(0.0), m_adj_v(0.0), m_lumaRed(0.0), m_lumaGreen(0.0), m_lumaBlue(0.0), m_type(0), m_colorize(false) { } public: void transform(const quint8 *srcU8, quint8 *dstU8, qint32 nPixels) const override { //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(srcU8); RGBPixel* dst = reinterpret_cast(dstU8); float h, s, v; float r = 0.0; float g = 0.0; float b = 0.0; qreal lumaR, lumaG, lumaB; //Default to rec 709 when there's no coefficients given// if (m_lumaRed<=0 || m_lumaGreen<=0 || m_lumaBlue<=0) { lumaR = 0.2126; lumaG = 0.7152; lumaB = 0.0722; } else { lumaR = m_lumaRed; lumaG = m_lumaGreen; lumaB = m_lumaBlue; } while (nPixels > 0) { if (m_colorize) { h = m_adj_h * 360; if (h >= 360.0) h = 0; s = m_adj_s; r = SCALE_TO_FLOAT(src->red); g = SCALE_TO_FLOAT(src->green); b = SCALE_TO_FLOAT(src->blue); float luminance = r * lumaR + g * lumaG + b * lumaB; if (m_adj_v > 0) { luminance *= (1.0 - m_adj_v); luminance += 1.0 - (1.0 - m_adj_v); } else if (m_adj_v < 0 ){ luminance *= (m_adj_v + 1.0); } v = luminance; HSLToRGB(h, s, v, &r, &g, &b); } else { if (m_type == 0) { RGBToHSV(SCALE_TO_FLOAT(src->red), SCALE_TO_FLOAT(src->green), SCALE_TO_FLOAT(src->blue), &h, &s, &v); h += m_adj_h * 180; if (h > 360) h -= 360; if (h < 0) h += 360; s += m_adj_s; v += m_adj_v; HSVToRGB(h, s, v, &r, &g, &b); } else if (m_type == 1) { RGBToHSL(SCALE_TO_FLOAT(src->red), SCALE_TO_FLOAT(src->green), SCALE_TO_FLOAT(src->blue), &h, &s, &v); h += m_adj_h * 180; if (h > 360) h -= 360; if (h < 0) h += 360; s *= (m_adj_s + 1.0); if (s < 0.0) s = 0.0; if (s > 1.0) s = 1.0; if (m_adj_v < 0) v *= (m_adj_v + 1.0); else v += (m_adj_v * (1.0 - v)); HSLToRGB(h, s, v, &r, &g, &b); } else if (m_type == 2) { qreal red = SCALE_TO_FLOAT(src->red); qreal green = SCALE_TO_FLOAT(src->green); qreal blue = SCALE_TO_FLOAT(src->blue); qreal hue, sat, intensity; RGBToHCI(red, green, blue, &hue, &sat, &intensity); hue *=360.0; hue += m_adj_h * 180; //if (intensity+m_adj_v>1.0){hue+=180.0;} if (hue < 0) hue += 360; hue = fmod(hue, 360.0); 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); r = red; g = green; b = blue; } else if (m_type == 3) { qreal red = SCALE_TO_FLOAT(src->red); qreal green = SCALE_TO_FLOAT(src->green); qreal blue = SCALE_TO_FLOAT(src->blue); qreal hue, sat, luma; RGBToHCY(red, green, blue, &hue, &sat, &luma, lumaR, lumaG, lumaB); hue *=360.0; hue += m_adj_h * 180; //if (luma+m_adj_v>1.0){hue+=180.0;} if (hue < 0) hue += 360; hue = fmod(hue, 360.0); sat *= (m_adj_s + 1.0); //sat = qBound(0.0, sat, 1.0); luma += m_adj_v; HCYToRGB(hue/360.0, sat, luma, &red, &green, &blue, lumaR, lumaG, lumaB); r = red; g = green; b = blue; - + } else if (m_type == 4) { qreal red = SCALE_TO_FLOAT(src->red); qreal green = SCALE_TO_FLOAT(src->green); qreal blue = SCALE_TO_FLOAT(src->blue); qreal y, cb, cr; RGBToYUV(red, green, blue, &y, &cb, &cr, lumaR, lumaG, lumaB); cb *= (m_adj_h + 1.0); //cb = qBound(0.0, cb, 1.0); cr *= (m_adj_s + 1.0); //cr = qBound(0.0, cr, 1.0); y += (m_adj_v); YUVToRGB(y, cb, cr, &red, &green, &blue, lumaR, lumaG, lumaB); r = red; g = green; b = blue; } else { Q_ASSERT_X(false, "", "invalid type"); } } clamp< _channel_type_ >(&r, &g, &b); dst->red = SCALE_FROM_FLOAT(r); dst->green = SCALE_FROM_FLOAT(g); dst->blue = SCALE_FROM_FLOAT(b); dst->alpha = src->alpha; --nPixels; ++src; ++dst; } /*} else if (m_model="LABA"){ const LABPixel* src = reinterpret_cast(srcU8); LABPixel* dst = reinterpret_cast(dstU8); qreal lightness = SCALE_TO_FLOAT(src->L); 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); a = qBound(0.0, a, 1.0); b *= (m_adj_s + 1.0); b = qBound(0.0, b, 1.0); if (m_adj_v < 0) lightness *= (m_adj_v + 1.0); else lightness += (m_adj_v * (1.0 - lightness)); } else {//lch LABToLCH(lightness, a, b, &L, &C, &H); H *=360; H += m_adj_h * 180; if (H > 360) h -= 360; if (H < 0) h += 360; C += m_adj_s; C = qBound(0.0,C,1.0); L += m_adj_v; L = qBound(0.0,L,1.0); LCHToLAB(L, C, H/360.0, &lightness, &a, &b); } clamp< _channel_type_ >(&lightness, &a, &b); dst->L = SCALE_FROM_FLOAT(lightness); dst->a = SCALE_FROM_FLOAT(a); dst->b = SCALE_FROM_FLOAT(b); dst->alpha = src->alpha; --nPixels; ++src; ++dst; } }*/ } QList parameters() const override { QList list; list << "h" << "s" << "v" << "type" << "colorize" << "lumaRed" << "lumaGreen"<< "lumaBlue"; return list; } int parameterId(const QString& name) const override { if (name == "h") { return 0; } else if (name == "s") { return 1; } else if (name == "v") { return 2; } else if (name == "type") { return 3; } else if (name == "colorize") { return 4; } else if (name == "lumaRed") { return 5; } else if (name == "lumaGreen") { return 6; } else if (name == "lumaBlue") { return 7; } 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) * (s)aturation in range <-1.0, 1.0> ( for user, show -100, 100, or 0, 100 for colorize) * (v)alue in range <-1.0, 1.0> (for user, show -100, 100) * type: 0:HSV, 1:HSL, 2:HSI, 3:HSY, 4:YUV * m_colorize: Use colorize formula instead * luma Red/Green/Blue: Used for luma calculations. */ void setParameter(int id, const QVariant& parameter) override { switch(id) { case 0: m_adj_h = parameter.toDouble(); break; case 1: m_adj_s = parameter.toDouble(); break; case 2: m_adj_v = parameter.toDouble(); break; case 3: m_type = parameter.toInt(); break; case 4: m_colorize = parameter.toBool(); break; case 5: m_lumaRed = parameter.toDouble(); break; case 6: m_lumaGreen = parameter.toDouble(); break; case 7: m_lumaBlue = parameter.toDouble(); break; default: KIS_ASSERT_RECOVER_NOOP(false && "Unknown parameter ID. Ignored!"); ; } } private: double m_adj_h, m_adj_s, m_adj_v; qreal m_lumaRed, m_lumaGreen, m_lumaBlue; int m_type; bool m_colorize; }; template class KisHSVCurveAdjustment : public KoColorTransformation { typedef traits RGBTrait; 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), m_lumaBlue(0.0) {} QList parameters() const override { QList list; - list << "curve" << "channel" << "driverChannel" << "relative" << "lumaRed" << "lumaGreen"<< "lumaBlue"; + list << "curve" << "channel" << "lumaRed" << "lumaGreen"<< "lumaBlue"; return list; } int parameterId(const QString& name) const override { if (name == "curve") { 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") { return PAR_LUMA_G; } else if (name == "lumaBlue") { return PAR_LUMA_B; } return -1; } /** * curve: adjustment curve as QVector * channel: which channel to adjust * 0 = hue, 1 = saturation, 2 = value * luma Red/Green/Blue: Used for luma calculations. */ void setParameter(int id, const QVariant& parameter) override { switch(id) { case PAR_CURVE: m_curve = parameter.value>(); break; - case PAR_CHANNEL: - case PAR_DRIVER_CHANNEL: { + case PAR_CHANNEL: { int channel = parameter.toInt(); - 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; - } + KIS_ASSERT_RECOVER_RETURN(0 <= channel && channel < 3 && "Channel must be 0, 1 or 2. Ignored!"); + m_channel = channel; } break; - case PAR_RELATIVE: - m_relative = parameter.toBool(); - break; case PAR_LUMA_R: m_lumaRed = parameter.toDouble(); break; case PAR_LUMA_G: m_lumaGreen = parameter.toDouble(); break; case PAR_LUMA_B: m_lumaBlue = parameter.toDouble(); break; default: KIS_ASSERT_RECOVER_NOOP(false && "Unknown parameter ID. Ignored!"); } } void transform(const quint8 *srcU8, quint8 *dstU8, qint32 nPixels) const override { const RGBPixel* src = reinterpret_cast(srcU8); RGBPixel* dst = reinterpret_cast(dstU8); - float max = m_curve.size() - 1; + float r = 0.0; + float g = 0.0; + float b = 0.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; + float max = m_curve.size() - 1; + float component[3]; + float &hue = component[0]; 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), - &h, &s, &v + &component[0], &component[1], &component[2] ); // Normalize hue to 0.0 to 1.0 range - h /= 360.0f; + hue /= 360.0f; - float adjustment = lookupComponent(component[driverChannel], max); - if (m_relative) { - component[m_channel] += adjustment - 0.5f; // fixme: ducttape - } else { - component[m_channel] = adjustment; - } + component[m_channel] = lookupComponent(component[m_channel], max); - h *= 360.0f; + hue *= 360.0f; + if (hue > 360) hue -= 360; + if (hue < 0) hue += 360; - if (h > 360) h -= 360; - if (h < 0) h += 360; - - if (m_channel > chBlue) { - HSVToRGB(h, s, v, &r, &g, &b); - } + HSVToRGB(component[0], component[1], component[2], &r, &g, &b); clamp< _channel_type_ >(&r, &g, &b); dst->red = SCALE_FROM_FLOAT(r); dst->green = SCALE_FROM_FLOAT(g); dst->blue = SCALE_FROM_FLOAT(b); dst->alpha = src->alpha; --nPixels; ++src; ++dst; } } const float SCALE_FROM_16BIT = 1.0f / 0xFFFF; float lookupComponent(float x, float max) const { // 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); float offset = lookup - base; if (base >= max) { base = max - 1.0f; offset = 1.0f; } int index = (int)base; return ((1.0f - offset) * m_curve[index] + offset * m_curve[index + 1]) * SCALE_FROM_16BIT; } private: - enum enumParameterID + enum ParameterID { PAR_CURVE, PAR_CHANNEL, - PAR_DRIVER_CHANNEL, - PAR_RELATIVE, PAR_LUMA_R, PAR_LUMA_G, PAR_LUMA_B, }; QVector m_curve; - int m_channel = 0; - int m_driverChannel = 0; - bool m_relative = false; + int m_channel; /* Note: the filter currently only supports HSV, so these are * unused, but will be needed once HSL, etc. */ qreal m_lumaRed, m_lumaGreen, m_lumaBlue; }; KisHSVAdjustmentFactory::KisHSVAdjustmentFactory() : KoColorTransformationFactory("hsv_adjustment") { } QList< QPair< KoID, KoID > > KisHSVAdjustmentFactory::supportedModels() const { QList< QPair< KoID, KoID > > l; l.append(QPair< KoID, KoID >(RGBAColorModelID , Integer8BitsColorDepthID)); l.append(QPair< KoID, KoID >(RGBAColorModelID , Integer16BitsColorDepthID)); l.append(QPair< KoID, KoID >(RGBAColorModelID , Float16BitsColorDepthID)); l.append(QPair< KoID, KoID >(RGBAColorModelID , Float32BitsColorDepthID)); return l; } KoColorTransformation* KisHSVAdjustmentFactory::createTransformation(const KoColorSpace* colorSpace, QHash parameters) const { KoColorTransformation * adj; if (colorSpace->colorModelId() != RGBAColorModelID) { dbgKrita << "Unsupported color space " << colorSpace->id() << " in KisHSVAdjustmentFactory::createTransformation"; return 0; } if (colorSpace->colorDepthId() == Integer8BitsColorDepthID) { adj = new KisHSVAdjustment< quint8, KoBgrTraits < quint8 > >(); } else if (colorSpace->colorDepthId() == Integer16BitsColorDepthID) { adj = new KisHSVAdjustment< quint16, KoBgrTraits < quint16 > >(); } #ifdef HAVE_OPENEXR else if (colorSpace->colorDepthId() == Float16BitsColorDepthID) { adj = new KisHSVAdjustment< half, KoRgbTraits < half > >(); } #endif else if (colorSpace->colorDepthId() == Float32BitsColorDepthID) { adj = new KisHSVAdjustment< float, KoRgbTraits < float > >(); } else { dbgKrita << "Unsupported color space " << colorSpace->id() << " in KisHSVAdjustmentFactory::createTransformation"; return 0; } adj->setParameters(parameters); return adj; } KisHSVCurveAdjustmentFactory::KisHSVCurveAdjustmentFactory() : KoColorTransformationFactory("hsv_curve_adjustment") { } QList< QPair< KoID, KoID > > KisHSVCurveAdjustmentFactory::supportedModels() const { QList< QPair< KoID, KoID > > l; l.append(QPair< KoID, KoID >(RGBAColorModelID , Integer8BitsColorDepthID)); l.append(QPair< KoID, KoID >(RGBAColorModelID , Integer16BitsColorDepthID)); l.append(QPair< KoID, KoID >(RGBAColorModelID , Float16BitsColorDepthID)); l.append(QPair< KoID, KoID >(RGBAColorModelID , Float32BitsColorDepthID)); return l; } KoColorTransformation* KisHSVCurveAdjustmentFactory::createTransformation(const KoColorSpace* colorSpace, QHash parameters) const { KoColorTransformation * adj; if (colorSpace->colorModelId() != RGBAColorModelID) { dbgKrita << "Unsupported color space " << colorSpace->id() << " in KisHSVCurveAdjustmentFactory::createTransformation"; return 0; } if (colorSpace->colorDepthId() == Integer8BitsColorDepthID) { adj = new KisHSVCurveAdjustment< quint8, KoBgrTraits < quint8 > >(); } else if (colorSpace->colorDepthId() == Integer16BitsColorDepthID) { adj = new KisHSVCurveAdjustment< quint16, KoBgrTraits < quint16 > >(); } #ifdef HAVE_OPENEXR else if (colorSpace->colorDepthId() == Float16BitsColorDepthID) { adj = new KisHSVCurveAdjustment< half, KoRgbTraits < half > >(); } #endif else if (colorSpace->colorDepthId() == Float32BitsColorDepthID) { adj = new KisHSVCurveAdjustment< float, KoRgbTraits < float > >(); } else { dbgKrita << "Unsupported color space " << colorSpace->id() << " in KisHSVCurveAdjustmentFactory::createTransformation"; return 0; } adj->setParameters(parameters); return adj; } diff --git a/plugins/filters/colorsfilters/CMakeLists.txt b/plugins/filters/colorsfilters/CMakeLists.txt index 2d5e7be9dd..90784342c7 100644 --- a/plugins/filters/colorsfilters/CMakeLists.txt +++ b/plugins/filters/colorsfilters/CMakeLists.txt @@ -1,21 +1,19 @@ 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 ) ki18n_wrap_ui(kritacolorsfilters_SOURCES wdg_perchannel.ui wdg_color_balance.ui wdg_hsv_adjustment.ui wdg_desaturate.ui ) add_library(kritacolorsfilters MODULE ${kritacolorsfilters_SOURCES}) target_link_libraries(kritacolorsfilters kritaui) install(TARGETS kritacolorsfilters DESTINATION ${KRITA_PLUGIN_INSTALL_DIR}) diff --git a/plugins/filters/colorsfilters/colorsfilters.cpp b/plugins/filters/colorsfilters/colorsfilters.cpp index 51635d0ed3..1091a1c697 100644 --- a/plugins/filters/colorsfilters/colorsfilters.cpp +++ b/plugins/filters/colorsfilters/colorsfilters.cpp @@ -1,175 +1,173 @@ /* * This file is part of Krita * * Copyright (c) 2004 Cyrille Berger * * 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 "colorsfilters.h" #include #include #include #include #include #include #include #include #include #include "KoBasicHistogramProducers.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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" K_PLUGIN_FACTORY_WITH_JSON(ColorsFiltersFactory, "kritacolorsfilter.json", registerPlugin();) ColorsFilters::ColorsFilters(QObject *parent, const QVariantList &) : QObject(parent) { 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()); } ColorsFilters::~ColorsFilters() { } //================================================================== KisAutoContrast::KisAutoContrast() : KisFilter(id(), categoryAdjust(), i18n("&Auto Contrast")) { setSupportsPainting(false); setSupportsThreading(false); setSupportsAdjustmentLayers(false); setColorSpaceIndependence(TO_LAB16); setShowConfigurationWidget(false); } void KisAutoContrast::processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const { Q_ASSERT(device != 0); Q_UNUSED(config); // initialize KoHistogramProducer *producer = new KoGenericLabHistogramProducer(); KisHistogram histogram(device, applyRect, producer, LINEAR); int minvalue = int(255 * histogram.calculations().getMin() + 0.5); int maxvalue = int(255 * histogram.calculations().getMax() + 0.5); if (maxvalue > 255) maxvalue = 255; histogram.setChannel(0); int twoPercent = int(0.005 * histogram.calculations().getCount()); int pixCount = 0; int binnum = 0; while (binnum < histogram.producer()->numberOfBins()) { pixCount += histogram.getValue(binnum); if (pixCount > twoPercent) { minvalue = binnum; break; } binnum++; } pixCount = 0; binnum = histogram.producer()->numberOfBins() - 1; while (binnum > 0) { pixCount += histogram.getValue(binnum); if (pixCount > twoPercent) { maxvalue = binnum; break; } binnum--; } // build the transferfunction int diff = maxvalue - minvalue; quint16* transfer = new quint16[256]; for (int i = 0; i < 255; i++) transfer[i] = 0xFFFF; if (diff != 0) { for (int i = 0; i < minvalue; i++) transfer[i] = 0x0; for (int i = minvalue; i < maxvalue; i++) { qint32 val = int((0xFFFF * (i - minvalue)) / diff); if (val > 0xFFFF) val = 0xFFFF; if (val < 0) val = 0; transfer[i] = val; } for (int i = maxvalue; i < 256; i++) transfer[i] = 0xFFFF; } // apply KoColorTransformation *adj = device->colorSpace()->createBrightnessContrastAdjustment(transfer); KisSequentialIteratorProgress it(device, applyRect, progressUpdater); quint32 npix = it.nConseqPixels(); while(it.nextPixels(npix)) { // adjust npix = it.nConseqPixels(); adj->transform(it.oldRawData(), it.rawData(), npix); } delete[] transfer; delete adj; } #include "colorsfilters.moc" diff --git a/plugins/filters/colorsfilters/kis_cross_channel_filter.cpp b/plugins/filters/colorsfilters/kis_cross_channel_filter.cpp deleted file mode 100644 index 7e0d892373..0000000000 --- a/plugins/filters/colorsfilters/kis_cross_channel_filter.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * This file is part of Krita - * - * Copyright (c) 2018 Jouni Pentikainen - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include - -#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 KisCrossChannelFilterConfiguration::driverChannels() const -{ - return m_driverChannels; -} - -void KisCrossChannelFilterConfiguration::setDriverChannels(QVector 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(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(config.data()); - Q_ASSERT(configBC); - - const QVector > &originalTransfers = configBC->transfers(); - const QList &curves = configBC->curves(); - const QVector &drivers = configBC->driverChannels(); - - const QVector virtualChannels = - KisMultiChannelFilterConfigurationBase::getVirtualChannels(cs); - - if (originalTransfers.size() != int(virtualChannels.size())) { - // We got an illegal number of colorchannels :( - return 0; - } - - QVector 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 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; -} diff --git a/plugins/filters/colorsfilters/kis_cross_channel_filter.h b/plugins/filters/colorsfilters/kis_cross_channel_filter.h deleted file mode 100644 index b4f716ed3d..0000000000 --- a/plugins/filters/colorsfilters/kis_cross_channel_filter.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of Krita - * - * Copyright (c) 2004 Cyrille Berger - * - * 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 -#include - -#include -#include -#include -#include -#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 &curves, int nCh); - - const QVector driverChannels() const; - void setDriverChannels(QVector driverChannels); - - using KisFilterConfiguration::fromXML; - using KisFilterConfiguration::toXML; - void fromXML(const QDomElement& e) override; - void toXML(QDomDocument& doc, QDomElement& root) const override; - -private: - QVector 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 m_driverChannels; -}; - -#endif diff --git a/plugins/filters/colorsfilters/kis_multichannel_filter_base.cpp b/plugins/filters/colorsfilters/kis_multichannel_filter_base.cpp deleted file mode 100644 index 45418106c4..0000000000 --- a/plugins/filters/colorsfilters/kis_multichannel_filter_base.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/* - * This file is part of Krita - * - * Copyright (c) 2005 C. Boemann - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include - -#include "kis_histogram.h" -#include "kis_painter.h" -#include "widgets/kis_curve_widget.h" - -QVector KisMultiChannelFilterConfigurationBase::getVirtualChannels(const KoColorSpace *cs) -{ - const bool supportsLightness = - cs->colorModelId() != LABAColorModelID && - cs->colorModelId() != GrayAColorModelID && - cs->colorModelId() != GrayColorModelID && - cs->colorModelId() != AlphaColorModelID; - - const bool supportsHue = supportsLightness; - const bool supportSaturation = supportsLightness; - - QVector vchannels; - - QList sortedChannels = - KoChannelInfo::displayOrderSorted(cs->channels()); - - if (supportsLightness) { - vchannels << VirtualChannelInfo(VirtualChannelInfo::ALL_COLORS, -1, 0, cs); - } - - Q_FOREACH (KoChannelInfo *channel, sortedChannels) { - int pixelIndex = KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), sortedChannels); - vchannels << VirtualChannelInfo(VirtualChannelInfo::REAL, pixelIndex, channel, cs); - } - - if (supportsHue) { - vchannels << VirtualChannelInfo(VirtualChannelInfo::HUE, -1, 0, cs); - } - - if (supportSaturation) { - vchannels << VirtualChannelInfo(VirtualChannelInfo::SATURATION, -1, 0, cs); - } - - if (supportsLightness) { - vchannels << VirtualChannelInfo(VirtualChannelInfo::LIGHTNESS, -1, 0, cs); - } - - return vchannels; -} - - -KisMultiChannelFilterConfigurationBase::KisMultiChannelFilterConfigurationBase(int channelCount, const QString & name, qint32 version) - : KisColorTransformationConfiguration(name, version) -{ - initDefaultCurves(m_curves, channelCount); - updateTransfers(); -} - -KisMultiChannelFilterConfigurationBase::~KisMultiChannelFilterConfigurationBase() -{} - -bool KisMultiChannelFilterConfigurationBase::isCompatible(const KisPaintDeviceSP dev) const -{ - return (int)dev->compositionSourceColorSpace()->channelCount() == m_curves.size(); -} - -void KisMultiChannelFilterConfigurationBase::setCurves(QList &curves) -{ - m_curves.clear(); - m_curves = curves; - - updateTransfers(); -} - -void KisMultiChannelFilterConfigurationBase::initDefaultCurves(QList &curves, int nCh) -{ - curves.clear(); - for (int i = 0; i < nCh; i++) { - curves.append(KisCubicCurve()); - } -} - -void KisMultiChannelFilterConfigurationBase::updateTransfers() -{ - m_transfers.resize(m_curves.size()); - for (int i = 0; i < m_curves.size(); i++) { - m_transfers[i] = m_curves[i].uint16Transfer(); - } -} - -const QVector >& -KisMultiChannelFilterConfigurationBase::transfers() const -{ - return m_transfers; -} - -const QList& -KisMultiChannelFilterConfigurationBase::curves() const -{ - return m_curves; -} - -void KisMultiChannelFilterConfigurationBase::fromLegacyXML(const QDomElement& root) -{ - fromXML(root); -} - -void KisMultiChannelFilterConfigurationBase::fromXML(const QDomElement& root) -{ - QList curves; - quint16 numTransfers = 0; - int version; - version = root.attribute("version").toInt(); - - QDomElement e = root.firstChild().toElement(); - QString attributeName; - KisCubicCurve curve; - quint16 index; - while (!e.isNull()) { - if ((attributeName = e.attribute("name")) == "nTransfers") { - numTransfers = e.text().toUShort(); - } else { - QRegExp rx("curve(\\d+)"); - if (rx.indexIn(attributeName, 0) != -1) { - - index = rx.cap(1).toUShort(); - index = qMin(index, quint16(curves.count())); - - if (!e.text().isEmpty()) { - curve.fromString(e.text()); - } - curves.insert(index, curve); - } - } - e = e.nextSiblingElement(); - } - - //prepend empty curves for the brightness contrast filter. - if(getString("legacy") == "brightnesscontrast") { - if (getString("colorModel") == LABAColorModelID.id()) { - curves.append(KisCubicCurve()); - curves.append(KisCubicCurve()); - curves.append(KisCubicCurve()); - } else { - int extraChannels = 5; - if (getString("colorModel") == CMYKAColorModelID.id()) { - extraChannels = 6; - } else if (getString("colorModel") == GrayAColorModelID.id()) { - extraChannels = 0; - } - for(int c = 0; c < extraChannels; c ++) { - curves.insert(0, KisCubicCurve()); - } - } - } - if (!numTransfers) - return; - - setVersion(version); - setCurves(curves); -} - -/** - * Inherited from KisPropertiesConfiguration - */ -//void KisMultiChannelFilterConfigurationBase::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 KisMultiChannelFilterConfigurationBase::toXML(QDomDocument& doc, QDomElement& root) const -{ - /** - * - * 3 - * 0,0;0.5,0.5;1,1; - * 0,0;1,1; - * 0,0;1,1; - * - */ - - root.setAttribute("version", version()); - - QDomText text; - QDomElement t; - - addParamNode(doc, root, "nTransfers", QString::number(m_curves.size())); - - KisCubicCurve curve; - QString paramName; - - for (int i = 0; i < m_curves.size(); ++i) { - QString name = QLatin1String("curve") + QString::number(i); - QString value = m_curves[i].toString(); - - addParamNode(doc, root, name, value); - } -} - - -KisMultiChannelConfigWidgetBase::KisMultiChannelConfigWidgetBase(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f) - : KisConfigWidget(parent, f) - , m_dev(dev) - , m_page(new WdgPerChannel(this)) -{ - Q_ASSERT(m_dev); - - const KoColorSpace *targetColorSpace = dev->compositionSourceColorSpace(); - m_virtualChannels = KisMultiChannelFilterConfigurationBase::getVirtualChannels(targetColorSpace); - - /* in subclass: - - // fill in the channel chooser, in the display order, but store the pixel index as well. - const int virtualChannelCount = m_virtualChannels.size(); - - KisMultiChannelFilterConfigurationBase::initDefaultCurves(m_curves, - virtualChannelCount); - init(m_page); - - */ -} - - -/** - * Initialize the dialog. - * Note: m_curves must be populated before calling this - */ -void KisMultiChannelConfigWidgetBase::init() { - QHBoxLayout * layout = new QHBoxLayout(this); - Q_CHECK_PTR(layout); - layout->setContentsMargins(0,0,0,0); - layout->addWidget(m_page); - - const int virtualChannelCount = m_virtualChannels.size(); - for (int i = 0; i < virtualChannelCount; i++) { - const VirtualChannelInfo &info = m_virtualChannels[i]; - - 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))); - connect((QObject*)(m_page->chkLogarithmic), SIGNAL(toggled(bool)), this, SLOT(logHistView())); - connect((QObject*)(m_page->resetButton), SIGNAL(clicked()), this, SLOT(resetCurve())); - - // create the horizontal and vertical gradient labels - m_page->hgradient->setPixmap(createGradient(Qt::Horizontal)); - m_page->vgradient->setPixmap(createGradient(Qt::Vertical)); - - // init histogram calculator - const KoColorSpace *targetColorSpace = m_dev->compositionSourceColorSpace(); - QList keys = - KoHistogramProducerFactoryRegistry::instance()->keysCompatibleWith(targetColorSpace); - - if(keys.size() > 0) { - KoHistogramProducerFactory *hpf; - hpf = KoHistogramProducerFactoryRegistry::instance()->get(keys.at(0)); - m_histogram = new KisHistogram(m_dev, m_dev->exactBounds(), hpf->generate(), LINEAR); - } - - connect(m_page->curveWidget, SIGNAL(modified()), this, SIGNAL(sigConfigurationItemChanged())); - - // TODO: needed? - //m_page->curveWidget->setupInOutControls(m_page->intIn, m_page->intOut, 0, 100); - - { - KisSignalsBlocker b(m_page->curveWidget); - m_page->curveWidget->setCurve(m_curves[0]); - setActiveChannel(0); - } -} - -KisMultiChannelConfigWidgetBase::~KisMultiChannelConfigWidgetBase() -{ - delete m_histogram; -} - -inline QPixmap KisMultiChannelConfigWidgetBase::createGradient(Qt::Orientation orient /*, int invert (not used yet) */) -{ - int width; - int height; - int *i, inc, col; - int x = 0, y = 0; - - if (orient == Qt::Horizontal) { - i = &x; inc = 1; col = 0; - width = 256; height = 1; - } else { - i = &y; inc = -1; col = 255; - width = 1; height = 256; - } - - QPixmap gradientpix(width, height); - QPainter p(&gradientpix); - p.setPen(QPen(QColor(0, 0, 0), 1, Qt::SolidLine)); - for (; *i < 256; (*i)++, col += inc) { - p.setPen(QColor(col, col, col)); - p.drawPoint(x, y); - } - return gradientpix; -} - -inline QPixmap KisMultiChannelConfigWidgetBase::getHistogram() -{ - int i; - int height = 256; - QPixmap pix(256, height); - KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_histogram, pix); - - - bool logarithmic = m_page->chkLogarithmic->isChecked(); - - if (logarithmic) - m_histogram->setHistogramType(LOGARITHMIC); - else - m_histogram->setHistogramType(LINEAR); - - - QPalette appPalette = QApplication::palette(); - - pix.fill(QColor(appPalette.color(QPalette::Base))); - - QPainter p(&pix); - p.setPen(QColor(appPalette.color(QPalette::Text))); - p.save(); - p.setOpacity(0.2); - - const VirtualChannelInfo &info = m_virtualChannels[m_activeVChannel]; - - - if (info.type() == VirtualChannelInfo::REAL) { - m_histogram->setChannel(info.pixelIndex()); - - double highest = (double)m_histogram->calculations().getHighest(); - - qint32 bins = m_histogram->producer()->numberOfBins(); - - if (m_histogram->getHistogramType() == LINEAR) { - double factor = (double)height / highest; - for (i = 0; i < bins; ++i) { - p.drawLine(i, height, i, height - int(m_histogram->getValue(i) * factor)); - } - } else { - double factor = (double)height / (double)log(highest); - for (i = 0; i < bins; ++i) { - p.drawLine(i, height, i, height - int(log((double)m_histogram->getValue(i)) * factor)); - } - } - } - - p.restore(); - - return pix; -} - -void KisMultiChannelConfigWidgetBase::setActiveChannel(int ch) -{ - 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(m_activeVChannel); - - updateChannelRange(); -} - -void KisMultiChannelConfigWidgetBase::logHistView() -{ - m_page->curveWidget->setPixmap(getHistogram()); -} - -void KisMultiChannelConfigWidgetBase::resetCurve() -{ - m_page->curveWidget->reset(); -} diff --git a/plugins/filters/colorsfilters/kis_multichannel_filter_base.h b/plugins/filters/colorsfilters/kis_multichannel_filter_base.h deleted file mode 100644 index 0d9a9c88fc..0000000000 --- a/plugins/filters/colorsfilters/kis_multichannel_filter_base.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This file is part of Krita - * - * Copyright (c) 2004 Cyrille Berger - * - * 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_MULTICHANNEL_FILTER_BASE_H_ -#define _KIS_MULTICHANNEL_FILTER_BASE_H_ - -#include -#include - -#include -#include -#include -#include -#include "ui_wdg_perchannel.h" - -#include "virtual_channel_info.h" - -/** - * - */ -class KisMultiChannelFilterConfigurationBase - : public KisColorTransformationConfiguration -{ -public: - KisMultiChannelFilterConfigurationBase(int channelCount, const QString & name, qint32 version); - ~KisMultiChannelFilterConfigurationBase() override; - - using KisFilterConfiguration::fromXML; - using KisFilterConfiguration::toXML; - using KisFilterConfiguration::fromLegacyXML; - - static QVector getVirtualChannels(const KoColorSpace *cs); - - void fromLegacyXML(const QDomElement& root) override; - - void fromXML(const QDomElement& e) override; - void toXML(QDomDocument& doc, QDomElement& root) const override; - - void setCurves(QList &curves) override; - bool isCompatible(const KisPaintDeviceSP) const override; - - const QVector >& transfers() const; - const QList& curves() const override; - - // TODO: cleanup - static void initDefaultCurves(QList &curves, int nCh); - -protected: - QList m_curves; - QVector > m_transfers; - - void updateTransfers(); -}; - -class WdgPerChannel : public QWidget, public Ui::WdgPerChannel -{ - Q_OBJECT - -public: - WdgPerChannel(QWidget *parent) : QWidget(parent) { - setupUi(this); - } -}; - -/** - * - */ -class KisMultiChannelConfigWidgetBase : public KisConfigWidget -{ - Q_OBJECT - -public: - KisMultiChannelConfigWidgetBase(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f = 0); - ~KisMultiChannelConfigWidgetBase() override; - -// void setConfiguration(const KisPropertiesConfigurationSP config) override; -// KisPropertiesConfigurationSP configuration() const override; - -protected Q_SLOTS: - virtual void setActiveChannel(int ch); - void logHistView(); - void resetCurve(); - -protected: - void init(); - virtual void updateChannelRange() = 0; - - QVector m_virtualChannels; - int m_activeVChannel = 0; - - // private routines - inline QPixmap getHistogram(); - inline QPixmap createGradient(Qt::Orientation orient /*, int invert (not used now) */); - - // members - WdgPerChannel * m_page; - KisPaintDeviceSP m_dev; - KisHistogram *m_histogram; - mutable QList m_curves; - - // scales for displaying color numbers - double m_scale = 1.0; - double m_shift = 0.0; - bool checkReset = false; - - /* - - m_page-> - cmbChannel - chkLogarithmic - resetButton - hgradient, vgradient - curveWidget - - - */ -}; - -#endif diff --git a/plugins/filters/colorsfilters/kis_perchannel_filter.cpp b/plugins/filters/colorsfilters/kis_perchannel_filter.cpp index bea9cf6be0..d1c2d825da 100644 --- a/plugins/filters/colorsfilters/kis_perchannel_filter.cpp +++ b/plugins/filters/colorsfilters/kis_perchannel_filter.cpp @@ -1,372 +1,694 @@ /* * This file is part of Krita * * Copyright (c) 2005 C. Boemann * * 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 #include #include #include #include #include #include #include #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 #include #include #include #include "kis_histogram.h" #include "kis_painter.h" #include "widgets/kis_curve_widget.h" +QVector getVirtualChannels(const KoColorSpace *cs) +{ + const bool supportsLightness = + cs->colorModelId() != LABAColorModelID && + cs->colorModelId() != GrayAColorModelID && + cs->colorModelId() != GrayColorModelID && + cs->colorModelId() != AlphaColorModelID; + + const bool supportsHue = supportsLightness; + const bool supportSaturation = supportsLightness; + + QVector vchannels; + + QList sortedChannels = + KoChannelInfo::displayOrderSorted(cs->channels()); + + if (supportsLightness) { + vchannels << VirtualChannelInfo(VirtualChannelInfo::ALL_COLORS, -1, 0, cs); + } + + Q_FOREACH (KoChannelInfo *channel, sortedChannels) { + int pixelIndex = KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), sortedChannels); + vchannels << VirtualChannelInfo(VirtualChannelInfo::REAL, pixelIndex, channel, cs); + } + + if (supportsHue) { + vchannels << VirtualChannelInfo(VirtualChannelInfo::HUE, -1, 0, cs); + } + + if (supportSaturation) { + vchannels << VirtualChannelInfo(VirtualChannelInfo::SATURATION, -1, 0, cs); + } + + if (supportsLightness) { + vchannels << VirtualChannelInfo(VirtualChannelInfo::LIGHTNESS, -1, 0, cs); + } + + return vchannels; +} + KisPerChannelConfigWidget::KisPerChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f) - : KisMultiChannelConfigWidgetBase(parent, dev, f) + : KisConfigWidget(parent, f), m_histogram(0) { - KisMultiChannelFilterConfigurationBase::initDefaultCurves(m_curves, m_virtualChannels.size()); - init(); + Q_ASSERT(dev); + m_page = new WdgPerChannel(this); + + QHBoxLayout * layout = new QHBoxLayout(this); + Q_CHECK_PTR(layout); + layout->setContentsMargins(0,0,0,0); + layout->addWidget(m_page); + + m_dev = dev; + m_activeVChannel = 0; + const KoColorSpace *targetColorSpace = dev->compositionSourceColorSpace(); + + // fill in the channel chooser, in the display order, but store the pixel index as well. + + m_virtualChannels = getVirtualChannels(targetColorSpace); + const int virtualChannelCount = m_virtualChannels.size(); + + KisPerChannelFilterConfiguration::initDefaultCurves(m_curves, + virtualChannelCount); + for (int i = 0; i < virtualChannelCount; i++) { + const VirtualChannelInfo &info = m_virtualChannels[i]; + + m_page->cmbChannel->addItem(info.name(), info.pixelIndex()); + m_curves[i].setName(info.name()); + } - // These are not used here, while the rest of the dialog - // is shared with KisCrossChannelConfigWidget - m_page->lblDriverChannel->hide(); - m_page->cmbDriverChannel->hide(); + connect(m_page->cmbChannel, SIGNAL(activated(int)), this, SLOT(setActiveChannel(int))); + connect((QObject*)(m_page->chkLogarithmic), SIGNAL(toggled(bool)), this, SLOT(logHistView())); + connect((QObject*)(m_page->resetButton), SIGNAL(clicked()), this, SLOT(resetCurve())); + + // create the horizontal and vertical gradient labels + m_page->hgradient->setPixmap(createGradient(Qt::Horizontal)); + m_page->vgradient->setPixmap(createGradient(Qt::Vertical)); + + // init histogram calculator + QList keys = + KoHistogramProducerFactoryRegistry::instance()->keysCompatibleWith(targetColorSpace); + + if(keys.size() > 0) { + KoHistogramProducerFactory *hpf; + hpf = KoHistogramProducerFactoryRegistry::instance()->get(keys.at(0)); + m_histogram = new KisHistogram(m_dev, m_dev->exactBounds(), hpf->generate(), LINEAR); + } + + connect(m_page->curveWidget, SIGNAL(modified()), this, SIGNAL(sigConfigurationItemChanged())); + + m_page->curveWidget->setupInOutControls(m_page->intIn, m_page->intOut, 0, 100); + + { + KisSignalsBlocker b(m_page->curveWidget); + m_page->curveWidget->setCurve(m_curves[0]); + setActiveChannel(0); + } } KisPerChannelConfigWidget::~KisPerChannelConfigWidget() -{} +{ + delete m_histogram; +} + +inline QPixmap KisPerChannelConfigWidget::createGradient(Qt::Orientation orient /*, int invert (not used yet) */) +{ + int width; + int height; + int *i, inc, col; + int x = 0, y = 0; + + if (orient == Qt::Horizontal) { + i = &x; inc = 1; col = 0; + width = 256; height = 1; + } else { + i = &y; inc = -1; col = 255; + width = 1; height = 256; + } + + QPixmap gradientpix(width, height); + QPainter p(&gradientpix); + p.setPen(QPen(QColor(0, 0, 0), 1, Qt::SolidLine)); + for (; *i < 256; (*i)++, col += inc) { + p.setPen(QColor(col, col, col)); + p.drawPoint(x, y); + } + return gradientpix; +} + +inline QPixmap KisPerChannelConfigWidget::getHistogram() +{ + int i; + int height = 256; + QPixmap pix(256, height); + KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_histogram, pix); + + + bool logarithmic = m_page->chkLogarithmic->isChecked(); + + if (logarithmic) + m_histogram->setHistogramType(LOGARITHMIC); + else + m_histogram->setHistogramType(LINEAR); + + + QPalette appPalette = QApplication::palette(); + + pix.fill(QColor(appPalette.color(QPalette::Base))); + + QPainter p(&pix); + p.setPen(QColor(appPalette.color(QPalette::Text))); + p.save(); + p.setOpacity(0.2); + + const VirtualChannelInfo &info = m_virtualChannels[m_activeVChannel]; + + + if (info.type() == VirtualChannelInfo::REAL) { + m_histogram->setChannel(info.pixelIndex()); + + double highest = (double)m_histogram->calculations().getHighest(); + + qint32 bins = m_histogram->producer()->numberOfBins(); + + if (m_histogram->getHistogramType() == LINEAR) { + double factor = (double)height / highest; + for (i = 0; i < bins; ++i) { + p.drawLine(i, height, i, height - int(m_histogram->getValue(i) * factor)); + } + } else { + double factor = (double)height / (double)log(highest); + for (i = 0; i < bins; ++i) { + p.drawLine(i, height, i, height - int(log((double)m_histogram->getValue(i)) * factor)); + } + } + } + + p.restore(); + + return pix; +} #define BITS_PER_BYTE 8 #define pwr2(p) (1<curveWidget->curve(); + + m_activeVChannel = ch; + m_page->curveWidget->setCurve(m_curves[m_activeVChannel]); + m_page->curveWidget->setPixmap(getHistogram()); + m_page->cmbChannel->setCurrentIndex(m_activeVChannel); + // Getting range accepted by channel VirtualChannelInfo ¤tVChannel = 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 (valueType) { case KoChannelInfo::UINT8: case KoChannelInfo::UINT16: case KoChannelInfo::UINT32: m_shift = 0; m_scale = double(maxValue); min = 0; max = maxValue - 1; break; case KoChannelInfo::INT8: case KoChannelInfo::INT16: m_shift = 0.5; m_scale = double(maxValue); min = -maxValue / 2; max = maxValue / 2 - 1; break; case KoChannelInfo::FLOAT16: case KoChannelInfo::FLOAT32: case KoChannelInfo::FLOAT64: default: m_shift = 0; m_scale = 100.0; //Hack Alert: should be changed to float min = 0; max = 100; break; } m_page->curveWidget->setupInOutControls(m_page->intIn, m_page->intOut, min, max); } -KisPropertiesConfigurationSP KisPerChannelConfigWidget::configuration() const +KisPropertiesConfigurationSP KisPerChannelConfigWidget::configuration() const { int numChannels = m_virtualChannels.size(); KisPropertiesConfigurationSP cfg = new KisPerChannelFilterConfiguration(numChannels); KIS_ASSERT_RECOVER(m_activeVChannel < m_curves.size()) { return cfg; } m_curves[m_activeVChannel] = m_page->curveWidget->curve(); static_cast(cfg.data())->setCurves(m_curves); return cfg; } void KisPerChannelConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { const KisPerChannelFilterConfiguration * cfg = dynamic_cast(config.data()); if (!cfg) return; if (cfg->curves().size() == 0) { /** * HACK ALERT: our configuration factory generates * default configuration with nTransfers==0. * Catching it here. Just reset all the transfers. */ const int virtualChannelCount = m_virtualChannels.size(); - KisMultiChannelFilterConfigurationBase::initDefaultCurves(m_curves, + KisPerChannelFilterConfiguration::initDefaultCurves(m_curves, virtualChannelCount); for (int i = 0; i < virtualChannelCount; i++) { const VirtualChannelInfo &info = m_virtualChannels[i]; m_curves[i].setName(info.name()); } } else if (cfg->curves().size() != int(m_virtualChannels.size())) { warnKrita << "WARNING: trying to load a curve with incorrect number of channels!"; warnKrita << "WARNING: expected:" << m_virtualChannels.size(); warnKrita << "WARNING: got:" << cfg->curves().size(); return; } else { for (int ch = 0; ch < cfg->curves().size(); ch++) m_curves[ch] = cfg->curves()[ch]; } // HACK: we save the previous curve in setActiveChannel, so just copy it m_page->curveWidget->setCurve(m_curves[m_activeVChannel]); setActiveChannel(0); } -KisPerChannelFilterConfiguration::KisPerChannelFilterConfiguration(int channelCount) - : KisMultiChannelFilterConfigurationBase(channelCount, "perchannel", 1) -{} +KisPerChannelFilterConfiguration::KisPerChannelFilterConfiguration(int nCh) + : KisColorTransformationConfiguration("perchannel", 1) +{ + initDefaultCurves(m_curves, nCh); + updateTransfers(); +} KisPerChannelFilterConfiguration::~KisPerChannelFilterConfiguration() { } +bool KisPerChannelFilterConfiguration::isCompatible(const KisPaintDeviceSP dev) const +{ + return (int)dev->compositionSourceColorSpace()->channelCount() == m_curves.size(); +} + +void KisPerChannelFilterConfiguration::setCurves(QList &curves) +{ + m_curves.clear(); + m_curves = curves; + + updateTransfers(); +} + +void KisPerChannelFilterConfiguration::initDefaultCurves(QList &curves, int nCh) +{ + curves.clear(); + for (int i = 0; i < nCh; i++) { + curves.append(KisCubicCurve()); + } +} + +void KisPerChannelFilterConfiguration::updateTransfers() +{ + m_transfers.resize(m_curves.size()); + for (int i = 0; i < m_curves.size(); i++) { + m_transfers[i] = m_curves[i].uint16Transfer(); + } +} + +const QVector >& +KisPerChannelFilterConfiguration::transfers() const +{ + return m_transfers; +} + +const QList& +KisPerChannelFilterConfiguration::curves() const +{ + return m_curves; +} + +void KisPerChannelFilterConfiguration::fromLegacyXML(const QDomElement& root) +{ + fromXML(root); +} + void KisPerChannelFilterConfiguration::fromXML(const QDomElement& root) { - // TODO - KisColorTransformationConfiguration::fromXML(root); + QList curves; + quint16 numTransfers = 0; + int version; + version = root.attribute("version").toInt(); + + QDomElement e = root.firstChild().toElement(); + QString attributeName; + KisCubicCurve curve; + quint16 index; + while (!e.isNull()) { + if ((attributeName = e.attribute("name")) == "nTransfers") { + numTransfers = e.text().toUShort(); + } else { + QRegExp rx("curve(\\d+)"); + if (rx.indexIn(attributeName, 0) != -1) { + + index = rx.cap(1).toUShort(); + index = qMin(index, quint16(curves.count())); + + if (!e.text().isEmpty()) { + curve.fromString(e.text()); + } + curves.insert(index, curve); + } + } + e = e.nextSiblingElement(); + } + + //prepend empty curves for the brightness contrast filter. + if(getString("legacy") == "brightnesscontrast") { + if (getString("colorModel") == LABAColorModelID.id()) { + curves.append(KisCubicCurve()); + curves.append(KisCubicCurve()); + curves.append(KisCubicCurve()); + } else { + int extraChannels = 5; + if (getString("colorModel") == CMYKAColorModelID.id()) { + extraChannels = 6; + } else if (getString("colorModel") == GrayAColorModelID.id()) { + extraChannels = 0; + } + for(int c = 0; c < extraChannels; c ++) { + curves.insert(0, KisCubicCurve()); + } + } + } + if (!numTransfers) + return; + + setVersion(version); + setCurves(curves); +} + +/** + * Inherited from KisPropertiesConfiguration + */ +//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 { - // TODO - KisColorTransformationConfiguration::toXML(doc, root); + /** + * + * 3 + * 0,0;0.5,0.5;1,1; + * 0,0;1,1; + * 0,0;1,1; + * + */ + + root.setAttribute("version", version()); + + QDomText text; + QDomElement t; + + addParamNode(doc, root, "nTransfers", QString::number(m_curves.size())); + + KisCubicCurve curve; + QString paramName; + + for (int i = 0; i < m_curves.size(); ++i) { + QString name = QLatin1String("curve") + QString::number(i); + QString value = m_curves[i].toString(); + + addParamNode(doc, root, name, value); + } } -// KisPerChannelFilter +/** + * Inherited from KisPropertiesConfiguration + */ +//QString KisPerChannelFilterConfiguration::toXML() + KisPerChannelFilter::KisPerChannelFilter() : KisColorTransformationFilter(id(), categoryAdjust(), i18n("&Color Adjustment curves...")) { setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M)); setSupportsPainting(true); setColorSpaceIndependence(TO_LAB16); } KisConfigWidget * KisPerChannelFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { return new KisPerChannelConfigWidget(parent, dev); } KisFilterConfigurationSP KisPerChannelFilter::factoryConfiguration() const { return new KisPerChannelFilterConfiguration(0); } KoColorTransformation* KisPerChannelFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const { const KisPerChannelFilterConfiguration* configBC = dynamic_cast(config.data()); // Somehow, this shouldn't happen Q_ASSERT(configBC); const QVector > &originalTransfers = configBC->transfers(); const QList &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 virtualChannels = - KisMultiChannelFilterConfigurationBase::getVirtualChannels(cs); + const QVector virtualChannels = getVirtualChannels(cs); if (originalTransfers.size() != int(virtualChannels.size())) { // We got an illegal number of colorchannels :( return 0; } bool colorsNull = true; bool hueNull = true; bool saturationNull = true; bool lightnessNull = true; bool allColorsNull = true; int alphaIndexInReal = -1; QVector > realTransfers; QVector hueTransfer; QVector saturationTransfer; QVector lightnessTransfer; QVector 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::HUE) { KIS_ASSERT_RECOVER_NOOP(hueTransfer.isEmpty()); hueTransfer = originalTransfers[i]; if (hueNull && !originalCurves[i].isNull()) { hueNull = false; } } else if (virtualChannels[i].type() == VirtualChannelInfo::SATURATION) { KIS_ASSERT_RECOVER_NOOP(saturationTransfer.isEmpty()); saturationTransfer = originalTransfers[i]; if (saturationNull && !originalCurves[i].isNull()) { saturationNull = false; } } else if (virtualChannels[i].type() == VirtualChannelInfo::LIGHTNESS) { 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]; if (allColorsNull && !originalCurves[i].isNull()) { allColorsNull = false; } } } KoColorTransformation *hueTransform = 0; KoColorTransformation *saturationTransform = 0; 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 (!hueNull) { QHash params; params["curve"] = QVariant::fromValue(hueTransfer); - params["channel"] = 3; // see KisHSVCurveAdjustment::enumChannel - params["relative"] = false; + params["channel"] = 0; params["lumaRed"] = cs->lumaCoefficients()[0]; params["lumaGreen"] = cs->lumaCoefficients()[1]; params["lumaBlue"] = cs->lumaCoefficients()[2]; hueTransform = cs->createColorTransformation("hsv_curve_adjustment", params); } if (!saturationNull) { QHash params; params["curve"] = QVariant::fromValue(saturationTransfer); - params["channel"] = 4; // see KisHSVCurveAdjustment::enumChannel - params["relative"] = false; + params["channel"] = 1; params["lumaRed"] = cs->lumaCoefficients()[0]; params["lumaGreen"] = cs->lumaCoefficients()[1]; params["lumaBlue"] = cs->lumaCoefficients()[2]; saturationTransform = cs->createColorTransformation("hsv_curve_adjustment", params); } if (!lightnessNull) { lightnessTransform = cs->createBrightnessContrastAdjustment(lightnessTransfer.constData()); } 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)); } allColorsTransform = cs->createPerChannelAdjustment(allColorsTransfers); delete[] allColorsTransfers; } QVector allTransforms; allTransforms << colorTransform; allTransforms << allColorsTransform; allTransforms << hueTransform; allTransforms << saturationTransform; allTransforms << lightnessTransform; return KoCompositeColorTransformation::createOptimizedCompositeTransform(allTransforms); } bool KisPerChannelFilter::needsTransparentPixels(const KisFilterConfigurationSP config, const KoColorSpace *cs) const { Q_UNUSED(config); return cs->colorModelId() == AlphaColorModelID; } + +void KisPerChannelConfigWidget::logHistView() +{ + m_page->curveWidget->setPixmap(getHistogram()); +} + +void KisPerChannelConfigWidget::resetCurve() +{ + m_page->curveWidget->reset(); +} diff --git a/plugins/filters/colorsfilters/kis_perchannel_filter.h b/plugins/filters/colorsfilters/kis_perchannel_filter.h index 763c7c212d..3d6c6503e9 100644 --- a/plugins/filters/colorsfilters/kis_perchannel_filter.h +++ b/plugins/filters/colorsfilters/kis_perchannel_filter.h @@ -1,93 +1,139 @@ /* * This file is part of Krita * * Copyright (c) 2004 Cyrille Berger * * 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_PERCHANNEL_FILTER_H_ #define _KIS_PERCHANNEL_FILTER_H_ #include #include #include #include #include #include +#include "ui_wdg_perchannel.h" #include "virtual_channel_info.h" -#include "kis_multichannel_filter_base.h" + +class WdgPerChannel : public QWidget, public Ui::WdgPerChannel +{ + Q_OBJECT + +public: + WdgPerChannel(QWidget *parent) : QWidget(parent) { + setupUi(this); + } +}; class KisPerChannelFilterConfiguration - : public KisMultiChannelFilterConfigurationBase + : public KisColorTransformationConfiguration { public: - KisPerChannelFilterConfiguration(int channelCount); + KisPerChannelFilterConfiguration(int n); ~KisPerChannelFilterConfiguration() override; - /* using KisFilterConfiguration::fromXML; using KisFilterConfiguration::toXML; using KisFilterConfiguration::fromLegacyXML; - */ - using KisFilterConfiguration::fromXML; - using KisFilterConfiguration::toXML; + void fromLegacyXML(const QDomElement& root) override; + void fromXML(const QDomElement& e) override; void toXML(QDomDocument& doc, QDomElement& root) const override; + + void setCurves(QList &curves) override; + static inline void initDefaultCurves(QList &curves, int nCh); + bool isCompatible(const KisPaintDeviceSP) const override; + + const QVector >& transfers() const; + const QList& curves() const override; +private: + QList m_curves; + +private: + void updateTransfers(); +private: + QVector > m_transfers; }; /** - * This class is a filter to adjust channels independently + * This class is generic for filters that affect channel separately */ class KisPerChannelFilter : public KisColorTransformationFilter { public: KisPerChannelFilter(); public: 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("perchannel", i18n("Color Adjustment")); } private: }; -class KisPerChannelConfigWidget : public KisMultiChannelConfigWidgetBase +class KisPerChannelConfigWidget : public KisConfigWidget { Q_OBJECT public: KisPerChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f = 0); ~KisPerChannelConfigWidget() override; void setConfiguration(const KisPropertiesConfigurationSP config) override; - KisPropertiesConfigurationSP configuration() const override; + KisPropertiesConfigurationSP configuration() const override; + +private Q_SLOTS: + virtual void setActiveChannel(int ch); + void logHistView(); + void resetCurve(); + + +private: + + QVector m_virtualChannels; + int m_activeVChannel; + + + // private routines + inline QPixmap getHistogram(); + inline QPixmap createGradient(Qt::Orientation orient /*, int invert (not used now) */); + + // members + WdgPerChannel * m_page; + KisPaintDeviceSP m_dev; + KisHistogram *m_histogram; + mutable QList m_curves; -protected: - void updateChannelRange() override; + // scales for displaying color numbers + double m_scale; + double m_shift; + bool checkReset; }; #endif diff --git a/plugins/filters/colorsfilters/wdg_cross_channel.ui b/plugins/filters/colorsfilters/wdg_cross_channel.ui deleted file mode 100644 index 8587d1637b..0000000000 --- a/plugins/filters/colorsfilters/wdg_cross_channel.ui +++ /dev/null @@ -1,401 +0,0 @@ - - - WdgPerChannel - - - - 0 - 0 - 376 - 384 - - - - - 0 - 0 - - - - BrightnessCon - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 6 - - - - - QLayout::SetFixedSize - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Input: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Output: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 10 - 10 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 20 - 20 - - - - - - - - QLayout::SetDefaultConstraint - - - 0 - - - - - - 0 - 0 - - - - - 256 - 256 - - - - - 16777215 - 16777215 - - - - QFrame::Panel - - - QFrame::Sunken - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 1 - 0 - - - - - 256 - 256 - - - - - 16777215 - 16777215 - - - - - - - - - - - - 1 - 0 - - - - - 256 - 20 - - - - - 16777215 - 20 - - - - QFrame::Panel - - - QFrame::Sunken - - - true - - - - - - - - 0 - 0 - - - - - 20 - 256 - - - - - 20 - 16777215 - - - - QFrame::Panel - - - QFrame::Sunken - - - true - - - - - - - - - 6 - - - - - - 0 - 0 - - - - Channel: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - Qt::Horizontal - - - - 10 - 10 - - - - - - - - Logarithmic - - - - - - - - 0 - 0 - - - - Reset - - - - - - - - - - KisIntParseSpinBox - QSpinBox -
kis_int_parse_spin_box.h
-
- - KisCurveWidget - -
widgets/kis_curve_widget.h
-
-
- - cmbChannel - intIn - intOut - - - -
diff --git a/plugins/filters/colorsfilters/wdg_perchannel.ui b/plugins/filters/colorsfilters/wdg_perchannel.ui index d9b840a5ea..8587d1637b 100644 --- a/plugins/filters/colorsfilters/wdg_perchannel.ui +++ b/plugins/filters/colorsfilters/wdg_perchannel.ui @@ -1,411 +1,401 @@ WdgPerChannel 0 0 - 441 - 456 + 376 + 384 0 0 BrightnessCon 0 0 0 0 0 6 QLayout::SetFixedSize 0 0 0 0 16777215 16777215 Input: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 0 0 Output: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 0 0 Qt::Horizontal QSizePolicy::Expanding 20 20 Qt::Vertical QSizePolicy::Fixed 10 10 Qt::Horizontal QSizePolicy::Fixed 20 20 Qt::Horizontal QSizePolicy::Fixed 20 20 QLayout::SetDefaultConstraint 0 0 0 256 256 16777215 16777215 QFrame::Panel QFrame::Sunken 0 0 0 0 0 1 0 256 256 16777215 16777215 1 0 256 20 16777215 20 QFrame::Panel QFrame::Sunken true 0 0 20 256 20 16777215 QFrame::Panel QFrame::Sunken true - - - - - Logarithmic - - - - - - - - - - - 0 - 0 - - - - Reset - - - - + + + 6 + + 0 0 Channel: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + + + + Qt::Horizontal 10 10 - - - - - + + - Driver channel + Logarithmic - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 0 + 0 + + + + Reset KisIntParseSpinBox QSpinBox
kis_int_parse_spin_box.h
KisCurveWidget
widgets/kis_curve_widget.h
cmbChannel intIn intOut