diff options
Diffstat (limited to 'chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp')
-rw-r--r-- | chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp b/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp new file mode 100644 index 000000000..82748f4c8 --- /dev/null +++ b/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cpp @@ -0,0 +1,351 @@ +/* + * dlg_colorrange.cpp - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org> + * + * 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 <tqapplication.h> +#include <tqpushbutton.h> +#include <tqcheckbox.h> +#include <tqslider.h> +#include <tqcombobox.h> +#include <tqpixmap.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqcolor.h> +#include <tqradiobutton.h> + +#include <knuminput.h> +#include <tdelocale.h> +#include <kdebug.h> +#include <tdeaction.h> + +#include <kis_canvas_subject.h> +#include <kis_iterators_pixel.h> +#include <kis_layer.h> +#include <kis_paint_device.h> +#include <kis_selection.h> +#include <kis_selection_manager.h> +#include <kis_types.h> +#include <kis_undo_adapter.h> +#include <kis_view.h> +#include <kis_colorspace.h> +#include <kis_profile.h> +#include <kis_color_conversions.h> +#include <kis_selected_transaction.h> +#include <kis_cursor.h> + +#include "dlg_colorrange.h" +#include "wdg_colorrange.h" + +namespace { + +// XXX: Poynton says: hsv/hls is not what one ought to use for colour calculations. +// Unfortunately, I don't know enough to be able to use anything else. + + bool isReddish(int h) + { + return ((h > 330 && h < 360) || ( h > 0 && h < 40)); + } + + bool isYellowish(int h) + { + return (h> 40 && h < 65); + } + + bool isGreenish(int h) + { + return (h > 70 && h < 155); + } + + bool isCyanish(int h) + { + return (h > 150 && h < 190); + } + + bool isBlueish(int h) + { + return (h > 185 && h < 270); + } + + bool isMagentaish(int h) + { + return (h > 265 && h < 330); + } + + bool isHighlight(int v) + { + return (v > 200); + } + + bool isMidTone(int v) + { + return (v > 100 && v < 200); + } + + bool isShadow(int v) + { + return (v < 100); + } + +} + +TQ_UINT32 matchColors(const TQColor & c, enumAction action) +{ + int r = c.red(); + int g = c.green(); + int b = c.blue(); + + int h, s, v; + rgb_to_hsv(r, g, b, &h, &s, &v); + + + + // XXX: Map the degree in which the colors conform to the requirement + // to a range of selectedness between 0 and 255 + + // XXX: Implement out-of-gamut using lcms + + switch(action) { + + case REDS: + if (isReddish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case YELLOWS: + if (isYellowish(h)) { + return MAX_SELECTED; + } + else + return MIN_SELECTED; + case GREENS: + if (isGreenish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case CYANS: + if (isCyanish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case BLUES: + if (isBlueish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case MAGENTAS: + if (isMagentaish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case HIGHLIGHTS: + if (isHighlight(v)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case MIDTONES: + if (isMidTone(v)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case SHADOWS: + if (isShadow(v)) + return MAX_SELECTED; + else + return MIN_SELECTED; + }; + + return MIN_SELECTED; +} + + + +DlgColorRange::DlgColorRange( KisView * view, KisPaintDeviceSP dev, TQWidget * parent, const char * name) + : super (parent, name, true, i18n("Color Range"), Ok | Cancel, Ok) +{ + m_dev = dev; + m_view = view; + + m_subject = view->canvasSubject(); + + m_page = new WdgColorRange(this, "color_range"); + TQ_CHECK_PTR(m_page); + + setCaption(i18n("Color Range")); + setMainWidget(m_page); + resize(m_page->sizeHint()); + + if (m_dev->image()->undo()) m_transaction = new KisSelectedTransaction(i18n("Select by Color Range"), m_dev); + + if(! m_dev->hasSelection()) + m_dev->selection()->clear(); + m_selection = m_dev->selection(); + + updatePreview(); + + m_invert = false; + m_mode = SELECTION_ADD; + m_currentAction = REDS; + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); + + connect(this, TQT_SIGNAL(cancelClicked()), + this, TQT_SLOT(cancelClicked())); + + connect(m_page->chkInvert, TQT_SIGNAL(clicked()), + this, TQT_SLOT(slotInvertClicked())); + + connect(m_page->cmbSelect, TQT_SIGNAL(activated(int)), + this, TQT_SLOT(slotSelectionTypeChanged(int))); + + connect (m_page->radioAdd, TQT_SIGNAL(toggled(bool)), + this, TQT_SLOT(slotAdd(bool))); + + connect (m_page->radioSubtract, TQT_SIGNAL(toggled(bool)), + this, TQT_SLOT(slotSubtract(bool))); + + connect (m_page->bnSelect, TQT_SIGNAL(clicked()), + this, TQT_SLOT(slotSelectClicked())); + + connect (m_page->bnDeselect, TQT_SIGNAL(clicked()), + this, TQT_SLOT(slotDeselectClicked())); + +} + +DlgColorRange::~DlgColorRange() +{ + delete m_page; +} + + +void DlgColorRange::updatePreview() +{ + if (!m_selection) return; + + TQ_INT32 x, y, w, h; + m_dev->exactBounds(x, y, w, h); + TQPixmap pix = TQPixmap(m_selection->maskImage().smoothScale(350, 350, TQ_ScaleMin)); + m_subject->canvasController()->updateCanvas(); + m_page->pixSelection->setPixmap(pix); +} + +void DlgColorRange::okClicked() +{ + m_dev->setDirty(); + m_dev->emitSelectionChanged(); + + if (m_dev->image()->undo()) m_subject->undoAdapter()->addCommand(m_transaction); + accept(); +} + +void DlgColorRange::cancelClicked() +{ + if (m_dev->image()->undo()) m_transaction->unexecute(); + + m_subject->canvasController()->updateCanvas(); + reject(); +} + +void DlgColorRange::slotInvertClicked() +{ + m_invert = m_page->chkInvert->isChecked(); +} + +void DlgColorRange::slotSelectionTypeChanged(int index) +{ + m_currentAction = (enumAction)index; +} + +void DlgColorRange::slotSubtract(bool on) +{ + if (on) + m_mode = SELECTION_SUBTRACT; +} +void DlgColorRange::slotAdd(bool on) +{ + if (on) + m_mode = SELECTION_ADD; +} + +void DlgColorRange::slotSelectClicked() +{ + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + // XXX: Multithread this! + TQ_INT32 x, y, w, h; + m_dev->exactBounds(x, y, w, h); + KisColorSpace * cs = m_dev->colorSpace(); + TQ_UINT8 opacity; + for (int y2 = y; y2 < h - y; ++y2) { + KisHLineIterator hiter = m_dev->createHLineIterator(x, y2, w, false); + KisHLineIterator selIter = m_selection ->createHLineIterator(x, y2, w, true); + while (!hiter.isDone()) { + TQColor c; + + cs->toTQColor(hiter.rawData(), &c, &opacity); + // Don't try to select transparent pixels. + if (opacity > OPACITY_TRANSPARENT) { + TQ_UINT8 match = matchColors(c, m_currentAction); + + if (match) { + // Personally, I think the invert option a bit silly. But it's possible I don't quite understand it. BSAR. + if (!m_invert) { + if (m_mode == SELECTION_ADD) { + *(selIter.rawData()) = match; + } + else if (m_mode == SELECTION_SUBTRACT) { + TQ_UINT8 selectedness = *(selIter.rawData()); + if (match < selectedness) { + *(selIter.rawData()) = selectedness - match; + } + else { + *(selIter.rawData()) = 0; + } + } + } + else { + if (m_mode == SELECTION_ADD) { + TQ_UINT8 selectedness = *(selIter.rawData()); + if (match < selectedness) { + *(selIter.rawData()) = selectedness - match; + } + else { + *(selIter.rawData()) = 0; + } + } + else if (m_mode == SELECTION_SUBTRACT) { + *(selIter.rawData()) = match; + } + } + } + } + ++hiter; + ++selIter; + } + } + updatePreview(); + TQApplication::restoreOverrideCursor(); +} + +void DlgColorRange::slotDeselectClicked() +{ + m_dev->selection()->clear(); + updatePreview(); +} + + +#include "dlg_colorrange.moc" |