File indexing completed on 2024-06-09 04:27:22
0001 /* 0002 * This file is part of the KDE project 0003 * 0004 * SPDX-FileCopyrightText: 2016 Boudewijn Rempt <boud@valdyas.org> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "threshold.h" 0010 #include <stdlib.h> 0011 #include <vector> 0012 0013 #include <QPoint> 0014 #include <QTime> 0015 0016 #include <klocalizedstring.h> 0017 0018 #include <kis_debug.h> 0019 #include <kpluginfactory.h> 0020 0021 #include <filter/kis_filter_category_ids.h> 0022 #include <filter/kis_filter_registry.h> 0023 #include <kis_global.h> 0024 #include "KisLevelsSlider.h" 0025 #include "kis_histogram.h" 0026 #include <kis_layer.h> 0027 #include "kis_paint_device.h" 0028 #include "kis_painter.h" 0029 #include <kis_processing_information.h> 0030 #include <kis_selection.h> 0031 #include <kis_types.h> 0032 #include <KisSequentialIteratorProgress.h> 0033 #include <kis_signals_blocker.h> 0034 0035 #include <KoBasicHistogramProducers.h> 0036 #include "KoColorModelStandardIds.h" 0037 #include <KoColorSpace.h> 0038 #include <KoColorTransformation.h> 0039 #include <KoUpdater.h> 0040 #include <KisGlobalResourcesInterface.h> 0041 0042 K_PLUGIN_FACTORY_WITH_JSON(KritaThresholdFactory, "kritathreshold.json", registerPlugin<KritaThreshold>();) 0043 0044 KritaThreshold::KritaThreshold(QObject *parent, const QVariantList &) 0045 : QObject(parent) 0046 { 0047 KisFilterRegistry::instance()->add(new KisFilterThreshold()); 0048 } 0049 0050 KritaThreshold::~KritaThreshold() 0051 { 0052 } 0053 0054 KisFilterThreshold::KisFilterThreshold() 0055 : KisFilter(id(), FiltersCategoryAdjustId, i18n("&Threshold...")) 0056 { 0057 setColorSpaceIndependence(FULLY_INDEPENDENT); 0058 0059 setSupportsPainting(false); 0060 setShowConfigurationWidget(true); 0061 setSupportsLevelOfDetail(true); 0062 setSupportsAdjustmentLayers(true); 0063 setSupportsThreading(true); 0064 } 0065 0066 void KisFilterThreshold::processImpl(KisPaintDeviceSP device, 0067 const QRect& applyRect, 0068 const KisFilterConfigurationSP config, 0069 KoUpdater *progressUpdater) const 0070 { 0071 Q_ASSERT(!device.isNull()); 0072 0073 const int threshold = config->getInt("threshold"); 0074 0075 KoColor white(Qt::white, device->colorSpace()); 0076 KoColor black(Qt::black, device->colorSpace()); 0077 0078 KisSequentialIteratorProgress it(device, applyRect, progressUpdater); 0079 const int pixelSize = device->colorSpace()->pixelSize(); 0080 0081 while (it.nextPixel()) { 0082 if (device->colorSpace()->intensity8(it.oldRawData()) > threshold) { 0083 white.setOpacity(device->colorSpace()->opacityU8(it.oldRawData())); 0084 memcpy(it.rawData(), white.data(), pixelSize); 0085 } 0086 else { 0087 black.setOpacity(device->colorSpace()->opacityU8(it.oldRawData())); 0088 memcpy(it.rawData(), black.data(), pixelSize); 0089 } 0090 } 0091 0092 } 0093 0094 0095 KisFilterConfigurationSP KisFilterThreshold::defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const 0096 { 0097 KisFilterConfigurationSP config = factoryConfiguration(resourcesInterface); 0098 config->setProperty("threshold", 128); 0099 return config; 0100 } 0101 0102 KisConfigWidget *KisFilterThreshold::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev, bool) const 0103 { 0104 return new KisThresholdConfigWidget(parent, dev); 0105 } 0106 0107 KisThresholdConfigWidget::KisThresholdConfigWidget(QWidget * parent, KisPaintDeviceSP dev) 0108 : KisConfigWidget(parent) 0109 { 0110 Q_ASSERT(dev); 0111 m_page.setupUi(this); 0112 0113 m_page.thresholdGradient->setThreshold(0.5); 0114 m_page.intThreshold->setValue(128); 0115 0116 connect(m_page.intThreshold, SIGNAL(valueChanged(int)), SIGNAL(sigConfigurationItemChanged())); 0117 connect(m_page.intThreshold, QOverload<int>::of(&QSpinBox::valueChanged), 0118 [this](int value) 0119 { 0120 KisSignalsBlocker blocker(m_page.thresholdGradient); 0121 m_page.thresholdGradient->setThreshold(static_cast<qreal>(value) / 255.0); 0122 } 0123 ); 0124 connect(m_page.thresholdGradient, SIGNAL(thresholdChanged(qreal)), SIGNAL(sigConfigurationItemChanged())); 0125 connect(m_page.thresholdGradient, &KisThresholdSlider::thresholdChanged, 0126 [this](qreal value) 0127 { 0128 KisSignalsBlocker blocker(m_page.intThreshold); 0129 m_page.intThreshold->setValue(static_cast<int>(qRound(value * 255.0))); 0130 } 0131 ); 0132 0133 connect((QObject*)(m_page.chkLogarithmic), SIGNAL(toggled(bool)), this, SLOT(slotDrawHistogram(bool))); 0134 0135 KoHistogramProducer *producer = new KoGenericLabHistogramProducer(); 0136 m_histogram.reset( new KisHistogram(dev, dev->exactBounds(), producer, LINEAR) ); 0137 m_histlog = false; 0138 m_page.histview->resize(288,100); 0139 slotDrawHistogram(); 0140 0141 } 0142 0143 KisThresholdConfigWidget::~KisThresholdConfigWidget() 0144 { 0145 } 0146 0147 void KisThresholdConfigWidget::slotDrawHistogram(bool logarithmic) 0148 { 0149 int wHeight = m_page.histview->height(); 0150 int wHeightMinusOne = wHeight - 1; 0151 int wWidth = m_page.histview->width(); 0152 0153 if (m_histlog != logarithmic) { 0154 // Update the m_histogram 0155 if (logarithmic) 0156 m_histogram->setHistogramType(LOGARITHMIC); 0157 else 0158 m_histogram->setHistogramType(LINEAR); 0159 m_histlog = logarithmic; 0160 } 0161 0162 QPalette appPalette = QApplication::palette(); 0163 QPixmap pix(wWidth-100, wHeight); 0164 0165 pix.fill(QColor(appPalette.color(QPalette::Base))); 0166 QPainter p(&pix); 0167 0168 p.setPen(QPen(Qt::gray, 1, Qt::SolidLine)); 0169 0170 double highest = (double)m_histogram->calculations().getHighest(); 0171 qint32 bins = m_histogram->producer()->numberOfBins(); 0172 0173 // use nearest neighbour interpolation 0174 if (m_histogram->getHistogramType() == LINEAR) { 0175 double factor = (double)(wHeight - wHeight / 5.0) / highest; 0176 for (int i = 0; i < wWidth; i++) { 0177 int binNo = qRound((double)i / wWidth * (bins - 1)); 0178 if ((int)m_histogram->getValue(binNo) != 0) 0179 p.drawLine(i, wHeightMinusOne, i, wHeightMinusOne - (int)m_histogram->getValue(binNo) * factor); 0180 } 0181 } else { 0182 double factor = (double)(wHeight - wHeight / 5.0) / (double)log(highest); 0183 for (int i = 0; i < wWidth; i++) { 0184 int binNo = qRound((double)i / wWidth * (bins - 1)) ; 0185 if ((int)m_histogram->getValue(binNo) != 0) 0186 p.drawLine(i, wHeightMinusOne, i, wHeightMinusOne - log((double)m_histogram->getValue(binNo)) * factor); 0187 } 0188 } 0189 0190 m_page.histview->setPixmap(pix); 0191 } 0192 0193 void KisThresholdConfigWidget::slotSetThreshold(int limit) 0194 { 0195 m_page.intThreshold->setMaximum(limit - 1); 0196 } 0197 0198 KisPropertiesConfigurationSP KisThresholdConfigWidget::configuration() const 0199 { 0200 KisFilterConfigurationSP config = new KisFilterConfiguration("threshold", 1, KisGlobalResourcesInterface::instance()); 0201 config->setProperty("threshold", m_page.intThreshold->value()); 0202 return config; 0203 } 0204 0205 void KisThresholdConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) 0206 { 0207 QVariant value; 0208 if (config->getProperty("threshold", value)) { 0209 KisSignalsBlocker blocker(m_page.intThreshold, m_page.thresholdGradient); 0210 m_page.intThreshold->setValue(value.toUInt()); 0211 m_page.thresholdGradient->setThreshold(static_cast<qreal>(value.toUInt()) / 255.0); 0212 } 0213 emit sigConfigurationItemChanged(); 0214 } 0215 0216 0217 #include "threshold.moc"