File indexing completed on 2024-06-16 04:16:38

0001 /*
0002  * This file is part of Krita
0003  *
0004  * SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "kis_perchannel_filter.h"
0010 
0011 #include <Qt>
0012 #include <QLayout>
0013 #include <QPixmap>
0014 #include <QPainter>
0015 #include <QLabel>
0016 #include <QComboBox>
0017 #include <QDomDocument>
0018 #include <QHBoxLayout>
0019 
0020 #include "KoChannelInfo.h"
0021 #include "KoBasicHistogramProducers.h"
0022 #include "KoColorModelStandardIds.h"
0023 #include "KoColorSpace.h"
0024 #include "KoColorTransformation.h"
0025 #include "KoCompositeColorTransformation.h"
0026 #include "KoCompositeOp.h"
0027 #include "KoID.h"
0028 
0029 #include "kis_signals_blocker.h"
0030 
0031 #include "kis_bookmarked_configuration_manager.h"
0032 #include "kis_config_widget.h"
0033 #include <filter/kis_filter_configuration.h>
0034 #include <kis_selection.h>
0035 #include <kis_paint_device.h>
0036 #include <kis_processing_information.h>
0037 
0038 #include "kis_histogram.h"
0039 #include "kis_painter.h"
0040 #include "widgets/kis_curve_widget.h"
0041 #include <KisGlobalResourcesInterface.h>
0042 
0043 #include "kis_multichannel_utils.h"
0044 
0045 KisPerChannelConfigWidget::KisPerChannelConfigWidget(QWidget * parent, KisPaintDeviceSP dev, Qt::WindowFlags f)
0046         : KisMultiChannelConfigWidget(parent, dev, f)
0047 {
0048     init();
0049 
0050     // These are not used by this filter,
0051     // but the dialog is shared with KisCrossChannelFilter
0052     m_page->lblDriverChannel->hide();
0053     m_page->cmbDriverChannel->hide();
0054 }
0055 
0056 KisPerChannelConfigWidget::~KisPerChannelConfigWidget()
0057 {}
0058 
0059 #define BITS_PER_BYTE 8
0060 #define pwr2(p) (1<<p)
0061 void KisPerChannelConfigWidget::updateChannelControls()
0062 {
0063     // Getting range accepted by channel
0064     VirtualChannelInfo &currentVChannel = m_virtualChannels[m_activeVChannel];
0065 
0066     KoChannelInfo::enumChannelValueType valueType = currentVChannel.valueType();
0067 
0068     int order = BITS_PER_BYTE * currentVChannel.channelSize();
0069     int maxValue = pwr2(order);
0070     int min;
0071     int max;
0072 
0073     m_curveControlsManager.reset();
0074 
0075     switch (valueType) {
0076     case KoChannelInfo::UINT8:
0077     case KoChannelInfo::UINT16:
0078     case KoChannelInfo::UINT32:
0079         min = 0;
0080         max = maxValue - 1;
0081         break;
0082     case KoChannelInfo::INT8:
0083     case KoChannelInfo::INT16:
0084         min = -maxValue / 2;
0085         max = maxValue / 2 - 1;
0086         break;
0087     case KoChannelInfo::FLOAT16:
0088     case KoChannelInfo::FLOAT32:
0089     case KoChannelInfo::FLOAT64:
0090     default:
0091         //Hack Alert: should be changed to float
0092         if (m_dev->colorSpace()->colorModelId() == LABAColorModelID || m_dev->colorSpace()->colorModelId() == CMYKAColorModelID) {
0093             if (m_dev->colorSpace()->channelCount() > m_activeVChannel) {
0094                 const QList<KoChannelInfo*> channels = m_dev->colorSpace()->channels();
0095                 min = channels[m_activeVChannel]->getUIMin();
0096                 max = channels[m_activeVChannel]->getUIMax();
0097             } else {
0098                 // it must be "Hue", "Saturation" or other "channel" that isn't actually accessible in the color space
0099                 min = 0;
0100                 // specific number apparently doesn't matter,
0101                 // if there is 255, it will work just fine, too
0102                 max = 100;
0103             }
0104         } else {
0105             min = 0;
0106             max = 100;
0107         }
0108         break;
0109     }
0110 
0111     m_curveControlsManager.reset(new KisCurveWidgetControlsManagerInt(m_page->curveWidget,
0112                                                                       m_page->intIn, m_page->intOut, min, max, min, max));
0113 }
0114 
0115 
0116 KisPropertiesConfigurationSP KisPerChannelConfigWidget::configuration() const
0117 {
0118     int numChannels = m_virtualChannels.size();
0119     KisPropertiesConfigurationSP cfg = new KisPerChannelFilterConfiguration(numChannels, KisGlobalResourcesInterface::instance());
0120 
0121     KIS_ASSERT_RECOVER(m_activeVChannel < m_curves.size()) { return cfg; }
0122 
0123     m_curves[m_activeVChannel] = m_page->curveWidget->curve();
0124     static_cast<KisPerChannelFilterConfiguration*>(cfg.data())->setCurves(m_curves);
0125 
0126     return cfg;
0127 }
0128 
0129 KisPropertiesConfigurationSP KisPerChannelConfigWidget::getDefaultConfiguration()
0130 {
0131     return new KisPerChannelFilterConfiguration(m_virtualChannels.size(), KisGlobalResourcesInterface::instance());
0132 }
0133 
0134 KisPerChannelFilterConfiguration::KisPerChannelFilterConfiguration(int channelCount, KisResourcesInterfaceSP resourcesInterface)
0135         : KisMultiChannelFilterConfiguration(channelCount, "perchannel", 1, resourcesInterface)
0136 {
0137     init();
0138 }
0139 
0140 KisPerChannelFilterConfiguration::KisPerChannelFilterConfiguration(const KisPerChannelFilterConfiguration &rhs)
0141     : KisMultiChannelFilterConfiguration(rhs)
0142 {
0143 }
0144 
0145 KisPerChannelFilterConfiguration::~KisPerChannelFilterConfiguration()
0146 {
0147 }
0148 
0149 KisFilterConfigurationSP KisPerChannelFilterConfiguration::clone() const
0150 {
0151     return new KisPerChannelFilterConfiguration(*this);
0152 }
0153 
0154 KisCubicCurve KisPerChannelFilterConfiguration::getDefaultCurve()
0155 {
0156     return KisCubicCurve();
0157 }
0158 
0159 // KisPerChannelFilter
0160 
0161 KisPerChannelFilter::KisPerChannelFilter() : KisMultiChannelFilter(id(), i18n("&Color Adjustment curves..."))
0162 {
0163     setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
0164 }
0165 
0166 KisConfigWidget * KisPerChannelFilter::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev, bool) const
0167 {
0168     return new KisPerChannelConfigWidget(parent, dev);
0169 }
0170 
0171 KisFilterConfigurationSP  KisPerChannelFilter::factoryConfiguration(KisResourcesInterfaceSP resourcesInterface) const
0172 {
0173     return new KisPerChannelFilterConfiguration(0, resourcesInterface);
0174 }
0175 
0176 KoColorTransformation* KisPerChannelFilter::createTransformation(const KoColorSpace* cs, const KisFilterConfigurationSP config) const
0177 {
0178     const KisPerChannelFilterConfiguration* configBC =
0179         dynamic_cast<const KisPerChannelFilterConfiguration*>(config.data()); // Somehow, this shouldn't happen
0180     Q_ASSERT(configBC);
0181 
0182     QList<bool> isIdentityList;
0183     for (const KisCubicCurve &curve : configBC->curves()) {
0184         isIdentityList.append(curve.isIdentity());
0185     }
0186 
0187     return KisMultiChannelUtils::createPerChannelTransformationFromTransfers(cs, configBC->transfers(), isIdentityList);
0188 }