File indexing completed on 2024-06-16 04:16:27
0001 /* 0002 * dlg_colorrange.cc - part of KimageShop^WKrayon^WKrita 0003 * 0004 * SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "dlg_colorrange.h" 0010 #include <QApplication> 0011 #include <QPushButton> 0012 #include <QCheckBox> 0013 #include <QSlider> 0014 #include <QComboBox> 0015 #include <QImage> 0016 #include <QLabel> 0017 #include <QColor> 0018 #include <QRadioButton> 0019 0020 #include <klocalizedstring.h> 0021 #include <kis_debug.h> 0022 0023 #include <KoColorConversions.h> 0024 #include <KoColorProfile.h> 0025 #include <KoColorSpace.h> 0026 #include <KoColor.h> 0027 #include <KoColorSpaceRegistry.h> 0028 #include <KoColorModelStandardIds.h> 0029 #include <KoColorSpaceTraits.h> 0030 0031 #include <kis_layer.h> 0032 #include <kis_paint_device.h> 0033 #include <kis_selection.h> 0034 #include <kis_selection_manager.h> 0035 #include <kis_default_bounds.h> 0036 #include <KisImageResolutionProxy.h> 0037 #include <kis_types.h> 0038 #include <kis_undo_adapter.h> 0039 #include <KisViewManager.h> 0040 #include <kis_transaction.h> 0041 #include <kis_cursor.h> 0042 #include "kis_iterator_ng.h" 0043 #include "kis_selection_tool_helper.h" 0044 #include <kis_slider_spin_box.h> 0045 #include <KisCursorOverrideLock.h> 0046 0047 DlgColorRange::DlgColorRange(KisViewManager *viewManager, QWidget *parent) 0048 : KoDialog(parent) 0049 , m_selectionCommandsAdded(0) 0050 , m_viewManager(viewManager) 0051 { 0052 setCaption(i18n("Color Range")); 0053 setButtons(Ok | Cancel); 0054 setDefaultButton(Ok); 0055 0056 m_page = new WdgColorRange(this); 0057 Q_CHECK_PTR(m_page); 0058 m_page->setObjectName("color_range"); 0059 0060 setCaption(i18n("Color Range")); 0061 setMainWidget(m_page); 0062 resize(m_page->sizeHint()); 0063 0064 m_page->intFuzziness->setObjectName("fuzziness"); 0065 m_page->intFuzziness->setRange(0, 200); 0066 m_page->intFuzziness->setSingleStep(10); 0067 m_page->intFuzziness->setValue(100); 0068 0069 m_invert = false; 0070 m_mode = SELECTION_ADD; 0071 m_currentAction = REDS; 0072 0073 connect(this, SIGNAL(okClicked()), 0074 this, SLOT(okClicked())); 0075 0076 connect(this, SIGNAL(cancelClicked()), 0077 this, SLOT(cancelClicked())); 0078 0079 connect(m_page->chkInvert, SIGNAL(clicked()), 0080 this, SLOT(slotInvertClicked())); 0081 0082 connect(m_page->cmbSelect, SIGNAL(activated(int)), 0083 this, SLOT(slotSelectionTypeChanged(int))); 0084 0085 connect(m_page->radioAdd, SIGNAL(toggled(bool)), 0086 this, SLOT(slotAdd(bool))); 0087 0088 connect(m_page->radioSubtract, SIGNAL(toggled(bool)), 0089 this, SLOT(slotSubtract(bool))); 0090 0091 connect(m_page->bnSelect, SIGNAL(clicked()), 0092 this, SLOT(slotSelectClicked())); 0093 0094 connect(m_page->bnDeselect, SIGNAL(clicked()), 0095 this, SLOT(slotDeselectClicked())); 0096 0097 m_page->bnDeselect->setEnabled(false); 0098 0099 } 0100 0101 DlgColorRange::~DlgColorRange() 0102 { 0103 delete m_page; 0104 } 0105 0106 void DlgColorRange::okClicked() 0107 { 0108 accept(); 0109 } 0110 0111 void DlgColorRange::cancelClicked() 0112 { 0113 if (!m_viewManager) return; 0114 if (!m_viewManager->image()) return; 0115 0116 for (int i = 0; i < m_selectionCommandsAdded; i++) { 0117 m_viewManager->undoAdapter()->undoLastCommand(); 0118 } 0119 m_viewManager->canvas()->update(); 0120 reject(); 0121 } 0122 0123 void DlgColorRange::slotInvertClicked() 0124 { 0125 m_invert = m_page->chkInvert->isChecked(); 0126 } 0127 0128 void DlgColorRange::slotSelectionTypeChanged(int index) 0129 { 0130 m_currentAction = (enumAction)index; 0131 } 0132 0133 void DlgColorRange::slotSubtract(bool on) 0134 { 0135 if (on) 0136 m_mode = SELECTION_SUBTRACT; 0137 } 0138 0139 void DlgColorRange::slotAdd(bool on) 0140 { 0141 if (on) 0142 m_mode = SELECTION_ADD; 0143 } 0144 0145 void DlgColorRange::slotSelectClicked() 0146 { 0147 KisPaintDeviceSP device = m_viewManager->activeDevice(); 0148 KIS_ASSERT_RECOVER_RETURN(device); 0149 0150 QRect rc = m_viewManager->image()->bounds(); 0151 0152 if (rc.isEmpty()) return; 0153 0154 KisCursorOverrideLock cursorLock(KisCursor::waitCursor()); 0155 0156 qint32 x, y, w, h; 0157 rc.getRect(&x, &y, &w, &h); 0158 0159 const KoColorSpace *cs = m_viewManager->activeDevice()->colorSpace(); 0160 const KoColorSpace *lab = KoColorSpaceRegistry::instance()->lab16(); 0161 0162 KoColor match; 0163 switch (m_currentAction) { 0164 case REDS: 0165 match = KoColor(QColor(Qt::red), cs); 0166 break; 0167 case YELLOWS: 0168 match = KoColor(QColor(Qt::yellow), cs); 0169 break; 0170 case GREENS: 0171 match = KoColor(QColor(Qt::green), cs); 0172 break; 0173 case CYANS: 0174 match = KoColor(QColor(Qt::cyan), cs); 0175 break; 0176 case BLUES: 0177 match = KoColor(QColor(Qt::blue), cs); 0178 break; 0179 case MAGENTAS: 0180 match = KoColor(QColor(Qt::magenta), cs); 0181 break; 0182 default: 0183 ; 0184 }; 0185 0186 int fuzziness = m_page->intFuzziness->value(); 0187 0188 KisSelectionSP selection = new KisSelection(new KisSelectionDefaultBounds(m_viewManager->activeDevice()), 0189 toQShared(new KisImageResolutionProxy(m_viewManager->image()))); 0190 0191 KisHLineConstIteratorSP hiter = m_viewManager->activeDevice()->createHLineConstIteratorNG(x, y, w); 0192 KisHLineIteratorSP selIter = selection->pixelSelection()->createHLineIteratorNG(x, y, w); 0193 0194 for (int row = y; row < h - y; ++row) { 0195 do { 0196 // Don't try to select transparent pixels. 0197 if (cs->opacityU8(hiter->oldRawData()) > OPACITY_TRANSPARENT_U8) { 0198 0199 bool selected = false; 0200 0201 KoColor c(hiter->oldRawData(), cs); 0202 if (m_currentAction > MAGENTAS) { 0203 c.convertTo(lab); 0204 quint8 L = lab->scaleToU8(c.data(), 0); 0205 0206 switch (m_currentAction) { 0207 case HIGHLIGHTS: 0208 selected = (L > MAX_SELECTED - fuzziness); 0209 break; 0210 case MIDTONES: 0211 selected = (L > MAX_SELECTED / 2 - fuzziness && L < MAX_SELECTED / 2 + fuzziness); 0212 break; 0213 case SHADOWS: 0214 selected = (L < MIN_SELECTED + fuzziness); 0215 break; 0216 default: 0217 ; 0218 } 0219 } 0220 else { 0221 quint8 difference = cs->difference(match.data(), c.data()); 0222 selected = (difference <= fuzziness); 0223 } 0224 0225 if (selected) { 0226 if (!m_invert) { 0227 if (m_mode == SELECTION_ADD) { 0228 *(selIter->rawData()) = MAX_SELECTED; 0229 } else if (m_mode == SELECTION_SUBTRACT) { 0230 *(selIter->rawData()) = MIN_SELECTED; 0231 } 0232 } else { 0233 if (m_mode == SELECTION_ADD) { 0234 *(selIter->rawData()) = MIN_SELECTED; 0235 } else if (m_mode == SELECTION_SUBTRACT) { 0236 *(selIter->rawData()) = MAX_SELECTED; 0237 } 0238 } 0239 } 0240 } 0241 } while (hiter->nextPixel() && selIter->nextPixel()); 0242 hiter->nextRow(); 0243 selIter->nextRow(); 0244 } 0245 0246 selection->pixelSelection()->invalidateOutlineCache(); 0247 KisSelectionToolHelper helper(m_viewManager->canvasBase(), kundo2_i18n("Color Range Selection")); 0248 helper.selectPixelSelection(selection->pixelSelection(), m_mode); 0249 0250 m_page->bnDeselect->setEnabled(true); 0251 m_selectionCommandsAdded++; 0252 } 0253 0254 void DlgColorRange::slotDeselectClicked() 0255 { 0256 if (!m_viewManager) return; 0257 0258 0259 m_viewManager->undoAdapter()->undoLastCommand(); 0260 m_selectionCommandsAdded--; 0261 if (!m_selectionCommandsAdded) { 0262 m_page->bnDeselect->setEnabled(false); 0263 } 0264 } 0265 0266