1 /*
2 * dlg_colorrange.cc - part of KimageShop^WKrayon^WKrita
3 *
4 * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include "dlg_colorrange.h"
22 #include <QApplication>
23 #include <QPushButton>
24 #include <QCheckBox>
25 #include <QSlider>
26 #include <QComboBox>
27 #include <QImage>
28 #include <QLabel>
29 #include <QColor>
30 #include <QRadioButton>
31
32 #include <klocalizedstring.h>
33 #include <kis_debug.h>
34
35 #include <KoColorConversions.h>
36 #include <KoColorProfile.h>
37 #include <KoColorSpace.h>
38 #include <KoColor.h>
39 #include <KoColorSpaceRegistry.h>
40 #include <KoColorModelStandardIds.h>
41 #include <KoColorSpaceTraits.h>
42
43 #include <kis_layer.h>
44 #include <kis_paint_device.h>
45 #include <kis_selection.h>
46 #include <kis_selection_manager.h>
47 #include <kis_types.h>
48 #include <kis_undo_adapter.h>
49 #include <KisViewManager.h>
50 #include <kis_transaction.h>
51 #include <kis_cursor.h>
52 #include "kis_iterator_ng.h"
53 #include "kis_selection_tool_helper.h"
54 #include <kis_slider_spin_box.h>
55
DlgColorRange(KisViewManager * viewManager,QWidget * parent)56 DlgColorRange::DlgColorRange(KisViewManager *viewManager, QWidget *parent)
57 : KoDialog(parent)
58 , m_selectionCommandsAdded(0)
59 , m_viewManager(viewManager)
60 {
61 setCaption(i18n("Color Range"));
62 setButtons(Ok | Cancel);
63 setDefaultButton(Ok);
64
65 m_page = new WdgColorRange(this);
66 Q_CHECK_PTR(m_page);
67 m_page->setObjectName("color_range");
68
69 setCaption(i18n("Color Range"));
70 setMainWidget(m_page);
71 resize(m_page->sizeHint());
72
73 m_page->intFuzziness->setObjectName("fuzziness");
74 m_page->intFuzziness->setRange(0, 200);
75 m_page->intFuzziness->setSingleStep(10);
76 m_page->intFuzziness->setValue(100);
77
78 m_invert = false;
79 m_mode = SELECTION_ADD;
80 m_currentAction = REDS;
81
82 connect(this, SIGNAL(okClicked()),
83 this, SLOT(okClicked()));
84
85 connect(this, SIGNAL(cancelClicked()),
86 this, SLOT(cancelClicked()));
87
88 connect(m_page->chkInvert, SIGNAL(clicked()),
89 this, SLOT(slotInvertClicked()));
90
91 connect(m_page->cmbSelect, SIGNAL(activated(int)),
92 this, SLOT(slotSelectionTypeChanged(int)));
93
94 connect(m_page->radioAdd, SIGNAL(toggled(bool)),
95 this, SLOT(slotAdd(bool)));
96
97 connect(m_page->radioSubtract, SIGNAL(toggled(bool)),
98 this, SLOT(slotSubtract(bool)));
99
100 connect(m_page->bnSelect, SIGNAL(clicked()),
101 this, SLOT(slotSelectClicked()));
102
103 connect(m_page->bnDeselect, SIGNAL(clicked()),
104 this, SLOT(slotDeselectClicked()));
105
106 m_page->bnDeselect->setEnabled(false);
107
108 }
109
~DlgColorRange()110 DlgColorRange::~DlgColorRange()
111 {
112 delete m_page;
113 }
114
okClicked()115 void DlgColorRange::okClicked()
116 {
117 accept();
118 }
119
cancelClicked()120 void DlgColorRange::cancelClicked()
121 {
122 if (!m_viewManager) return;
123 if (!m_viewManager->image()) return;
124
125 for (int i = 0; i < m_selectionCommandsAdded; i++) {
126 m_viewManager->undoAdapter()->undoLastCommand();
127 }
128 m_viewManager->canvas()->update();
129 reject();
130 }
131
slotInvertClicked()132 void DlgColorRange::slotInvertClicked()
133 {
134 m_invert = m_page->chkInvert->isChecked();
135 }
136
slotSelectionTypeChanged(int index)137 void DlgColorRange::slotSelectionTypeChanged(int index)
138 {
139 m_currentAction = (enumAction)index;
140 }
141
slotSubtract(bool on)142 void DlgColorRange::slotSubtract(bool on)
143 {
144 if (on)
145 m_mode = SELECTION_SUBTRACT;
146 }
147
slotAdd(bool on)148 void DlgColorRange::slotAdd(bool on)
149 {
150 if (on)
151 m_mode = SELECTION_ADD;
152 }
153
slotSelectClicked()154 void DlgColorRange::slotSelectClicked()
155 {
156 KisPaintDeviceSP device = m_viewManager->activeDevice();
157 KIS_ASSERT_RECOVER_RETURN(device);
158
159 QRect rc = m_viewManager->image()->bounds();
160
161 if (rc.isEmpty()) return;
162
163 QApplication::setOverrideCursor(KisCursor::waitCursor());
164
165 qint32 x, y, w, h;
166 rc.getRect(&x, &y, &w, &h);
167
168 const KoColorSpace *cs = m_viewManager->activeDevice()->colorSpace();
169 const KoColorSpace *lab = KoColorSpaceRegistry::instance()->lab16();
170
171 KoColor match;
172 switch (m_currentAction) {
173 case REDS:
174 match = KoColor(QColor(Qt::red), cs);
175 break;
176 case YELLOWS:
177 match = KoColor(QColor(Qt::yellow), cs);
178 break;
179 case GREENS:
180 match = KoColor(QColor(Qt::green), cs);
181 break;
182 case CYANS:
183 match = KoColor(QColor(Qt::cyan), cs);
184 break;
185 case BLUES:
186 match = KoColor(QColor(Qt::blue), cs);
187 break;
188 case MAGENTAS:
189 match = KoColor(QColor(Qt::magenta), cs);
190 break;
191 default:
192 ;
193 };
194
195 int fuzziness = m_page->intFuzziness->value();
196
197 KisSelectionSP selection = new KisSelection(new KisSelectionDefaultBounds(m_viewManager->activeDevice()));
198
199 KisHLineConstIteratorSP hiter = m_viewManager->activeDevice()->createHLineConstIteratorNG(x, y, w);
200 KisHLineIteratorSP selIter = selection->pixelSelection()->createHLineIteratorNG(x, y, w);
201
202 for (int row = y; row < h - y; ++row) {
203 do {
204 // Don't try to select transparent pixels.
205 if (cs->opacityU8(hiter->oldRawData()) > OPACITY_TRANSPARENT_U8) {
206
207 bool selected = false;
208
209 KoColor c(hiter->oldRawData(), cs);
210 if (m_currentAction > MAGENTAS) {
211 c.convertTo(lab);
212 quint8 L = lab->scaleToU8(c.data(), 0);
213
214 switch (m_currentAction) {
215 case HIGHLIGHTS:
216 selected = (L > MAX_SELECTED - fuzziness);
217 break;
218 case MIDTONES:
219 selected = (L > MAX_SELECTED / 2 - fuzziness && L < MAX_SELECTED / 2 + fuzziness);
220 break;
221 case SHADOWS:
222 selected = (L < MIN_SELECTED + fuzziness);
223 break;
224 default:
225 ;
226 }
227 }
228 else {
229 quint8 difference = cs->difference(match.data(), c.data());
230 selected = (difference <= fuzziness);
231 }
232
233 if (selected) {
234 if (!m_invert) {
235 if (m_mode == SELECTION_ADD) {
236 *(selIter->rawData()) = MAX_SELECTED;
237 } else if (m_mode == SELECTION_SUBTRACT) {
238 *(selIter->rawData()) = MIN_SELECTED;
239 }
240 } else {
241 if (m_mode == SELECTION_ADD) {
242 *(selIter->rawData()) = MIN_SELECTED;
243 } else if (m_mode == SELECTION_SUBTRACT) {
244 *(selIter->rawData()) = MAX_SELECTED;
245 }
246 }
247 }
248 }
249 } while (hiter->nextPixel() && selIter->nextPixel());
250 hiter->nextRow();
251 selIter->nextRow();
252 }
253
254 selection->pixelSelection()->invalidateOutlineCache();
255 KisSelectionToolHelper helper(m_viewManager->canvasBase(), kundo2_i18n("Color Range Selection"));
256 helper.selectPixelSelection(selection->pixelSelection(), m_mode);
257
258 m_page->bnDeselect->setEnabled(true);
259 m_selectionCommandsAdded++;
260 QApplication::restoreOverrideCursor();
261 }
262
slotDeselectClicked()263 void DlgColorRange::slotDeselectClicked()
264 {
265 if (!m_viewManager) return;
266
267
268 m_viewManager->undoAdapter()->undoLastCommand();
269 m_selectionCommandsAdded--;
270 if (!m_selectionCommandsAdded) {
271 m_page->bnDeselect->setEnabled(false);
272 }
273 }
274
275
276