From 166cb55c9753bea3a6624f5cb553ed2c6873cba5 Mon Sep 17 00:00:00 2001 From: David Capello Date: Fri, 9 Feb 2018 17:39:56 -0300 Subject: [PATCH] Add support for HSV color space in Adjust Hue/Saturation (fix #1559) --- data/pref.xml | 7 ++ .../commands/filters/cmd_hue_saturation.cpp | 64 ++++++++++++++++--- src/app/ui/color_sliders.cpp | 22 +++++++ src/app/ui/color_sliders.h | 4 +- src/filters/hue_saturation_filter.cpp | 43 ++++++++++--- src/filters/hue_saturation_filter.h | 10 ++- 6 files changed, 131 insertions(+), 19 deletions(-) diff --git a/data/pref.xml b/data/pref.xml index f21e548bd..c12466846 100644 --- a/data/pref.xml +++ b/data/pref.xml @@ -93,6 +93,10 @@ + + + + @@ -261,6 +265,9 @@ diff --git a/src/app/commands/filters/cmd_hue_saturation.cpp b/src/app/commands/filters/cmd_hue_saturation.cpp index 73dd86dfc..d05daa38f 100644 --- a/src/app/commands/filters/cmd_hue_saturation.cpp +++ b/src/app/commands/filters/cmd_hue_saturation.cpp @@ -15,6 +15,8 @@ #include "app/context.h" #include "app/ini_file.h" #include "app/modules/gui.h" +#include "app/pref/preferences.h" +#include "app/ui/button_set.h" #include "app/ui/color_button.h" #include "app/ui/color_sliders.h" #include "base/bind.h" @@ -40,25 +42,70 @@ public: WithChannelsSelector, WithoutTiledCheckBox) , m_filter(filter) + , m_colorType(2) { + getContainer()->addChild(&m_colorType); getContainer()->addChild(&m_sliders); + + auto mode = Preferences::instance().hueSaturation.mode(); + m_colorType.addItem("HSV")->setFocusStop(false); + m_colorType.addItem("HSL")->setFocusStop(false); + if (mode == gen::HueSaturationMode::HSV) + m_colorType.setSelectedItem(0); + else + m_colorType.setSelectedItem(1); + m_colorType.ItemChange.connect(base::Bind(&HueSaturationWindow::onChangeMode, this)); + m_sliders.setColorType(app::Color::HslType); m_sliders.setMode(ColorSliders::Mode::Relative); m_sliders.ColorChange.connect(base::Bind(&HueSaturationWindow::onChangeControls, this)); + + onChangeMode(); } private: + bool isHsl() const { + return (m_colorType.selectedItem() == 1); + } + + void onChangeMode() { + const int isHsl = this->isHsl(); + + Preferences::instance().hueSaturation.mode + (isHsl ? gen::HueSaturationMode::HSL: + gen::HueSaturationMode::HSV); + + m_filter.setMode(isHsl ? + HueSaturationFilter::Mode::HSL: + HueSaturationFilter::Mode::HSV); + + m_sliders.setColorType(isHsl ? + app::Color::HslType: + app::Color::HsvType); + + onChangeControls(); + } + void onChangeControls() { - m_filter.setHue( - double(m_sliders.getRelSliderValue(ColorSliders::Channel::HslHue))); - - m_filter.setSaturation( - m_sliders.getRelSliderValue(ColorSliders::Channel::HslSaturation) / 100.0); - - m_filter.setLightness( - m_sliders.getRelSliderValue(ColorSliders::Channel::HslLightness) / 100.0); + m_sliders.syncRelHsvHslSliders(); + if (isHsl()) { + m_filter.setHue( + double(m_sliders.getRelSliderValue(ColorSliders::Channel::HslHue))); + m_filter.setSaturation( + m_sliders.getRelSliderValue(ColorSliders::Channel::HslSaturation) / 100.0); + m_filter.setLightness( + m_sliders.getRelSliderValue(ColorSliders::Channel::HslLightness) / 100.0); + } + else { + m_filter.setHue( + double(m_sliders.getRelSliderValue(ColorSliders::Channel::HsvHue))); + m_filter.setSaturation( + m_sliders.getRelSliderValue(ColorSliders::Channel::HsvSaturation) / 100.0); + m_filter.setLightness( + m_sliders.getRelSliderValue(ColorSliders::Channel::HsvValue) / 100.0); + } m_filter.setAlpha( m_sliders.getRelSliderValue(ColorSliders::Channel::Alpha) / 100.0); @@ -66,6 +113,7 @@ private: } HueSaturationFilter& m_filter; + ButtonSet m_colorType; ColorSliders m_sliders; }; diff --git a/src/app/ui/color_sliders.cpp b/src/app/ui/color_sliders.cpp index da719464e..2b1baed90 100644 --- a/src/app/ui/color_sliders.cpp +++ b/src/app/ui/color_sliders.cpp @@ -393,6 +393,12 @@ void ColorSliders::setAbsSliderValue(const Channel i, int value) updateEntryText(i); } +void ColorSliders::setRelSliderValue(const Channel i, int value) +{ + m_items[i].relSlider->setValue(value); + updateEntryText(i); +} + int ColorSliders::getAbsSliderValue(const Channel i) const { return m_items[i].absSlider->getValue(); @@ -403,6 +409,22 @@ int ColorSliders::getRelSliderValue(const Channel i) const return m_items[i].relSlider->getValue(); } +void ColorSliders::syncRelHsvHslSliders() +{ + // From HSV -> HSL + if (m_items[Channel::HsvHue].show) { + setRelSliderValue(Channel::HslHue, getRelSliderValue(Channel::HsvHue)); + setRelSliderValue(Channel::HslSaturation, getRelSliderValue(Channel::HsvSaturation)); + setRelSliderValue(Channel::HslLightness, getRelSliderValue(Channel::HsvValue)); + } + // From HSL -> HSV + else if (m_items[Channel::HslHue].show) { + setRelSliderValue(Channel::HsvHue, getRelSliderValue(Channel::HslHue)); + setRelSliderValue(Channel::HsvSaturation, getRelSliderValue(Channel::HslSaturation)); + setRelSliderValue(Channel::HsvValue, getRelSliderValue(Channel::HslLightness)); + } +} + void ColorSliders::onSliderChange(const Channel i) { updateEntryText(i); diff --git a/src/app/ui/color_sliders.h b/src/app/ui/color_sliders.h index 3978ae494..ffc1c3e82 100644 --- a/src/app/ui/color_sliders.h +++ b/src/app/ui/color_sliders.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2017 David Capello +// Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -46,6 +46,7 @@ namespace app { int getAbsSliderValue(const Channel i) const; int getRelSliderValue(const Channel i) const; + void syncRelHsvHslSliders(); // Signals obs::signal ColorChange; @@ -59,6 +60,7 @@ namespace app { const int absMin, const int absMax, const int relMin, const int relMax); void setAbsSliderValue(const Channel i, int value); + void setRelSliderValue(const Channel i, int value); void updateSlidersVisibility(); void onSetColor(const app::Color& color); diff --git a/src/filters/hue_saturation_filter.cpp b/src/filters/hue_saturation_filter.cpp index 1582d0785..11ef48abf 100644 --- a/src/filters/hue_saturation_filter.cpp +++ b/src/filters/hue_saturation_filter.cpp @@ -16,6 +16,7 @@ #include "filters/filter_indexed_data.h" #include "filters/filter_manager.h" #include "gfx/hsl.h" +#include "gfx/hsv.h" #include "gfx/rgb.h" #include @@ -30,13 +31,19 @@ const char* HueSaturationFilter::getName() } HueSaturationFilter::HueSaturationFilter() - : m_h(0.0) + : m_mode(Mode::HSL) + , m_h(0.0) , m_s(0.0) , m_l(0.0) , m_a(0.0) { } +void HueSaturationFilter::setMode(Mode mode) +{ + m_mode = mode; +} + void HueSaturationFilter::setHue(double h) { m_h = h; @@ -93,7 +100,7 @@ void HueSaturationFilter::applyToRgba(FilterManager* filterMgr) c = fid->getNewPalette()->getEntry(i); } else { - applyHslFilterToRgb(target, c); + applyFilterToRgb(target, c); } *(dst_address++) = c; @@ -172,7 +179,7 @@ void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr) } color_t c = pal->getEntry(*(src_address++)); - applyHslFilterToRgb(target, c); + applyFilterToRgb(target, c); *(dst_address++) = rgbmap->mapColor(rgba_getr(c), rgba_getg(c), rgba_getb(c), @@ -195,21 +202,23 @@ void HueSaturationFilter::applyToPalette(FilterManager* filterMgr) } color_t c = pal->getEntry(i); - applyHslFilterToRgb(target, c); + applyFilterToRgb(target, c); newPal->setEntry(i, c); ++i; } } -void HueSaturationFilter::applyHslFilterToRgb( - const Target target, doc::color_t& c) +template +void HueSaturationFilter::applyFilterToRgbT(const Target target, doc::color_t& c) { int r = rgba_getr(c); int g = rgba_getg(c); int b = rgba_getb(c); int a = rgba_geta(c); - gfx::Hsl hsl(gfx::Rgb(r, g, b)); + T hsl(gfx::Rgb(r, g, b)); double h = hsl.hue() + m_h; while (h < 0.0) h += 360.0; @@ -218,12 +227,12 @@ void HueSaturationFilter::applyHslFilterToRgb( double s = hsl.saturation()*(1.0+m_s); s = MID(0.0, s, 1.0); - double l = hsl.lightness()*(1.0+m_l); + double l = (hsl.*get_lightness)()*(1.0+m_l); l = MID(0.0, l, 1.0); hsl.hue(h); hsl.saturation(s); - hsl.lightness(l); + (hsl.*set_lightness)(l); gfx::Rgb rgb(hsl); if (target & TARGET_RED_CHANNEL ) r = rgb.red(); @@ -237,4 +246,20 @@ void HueSaturationFilter::applyHslFilterToRgb( c = rgba(r, g, b, a); } +void HueSaturationFilter::applyFilterToRgb(const Target target, doc::color_t& color) +{ + switch (m_mode) { + case Mode::HSL: + applyFilterToRgbT(target, color); + break; + case Mode::HSV: + applyFilterToRgbT(target, color); + break; + } +} + } // namespace filters diff --git a/src/filters/hue_saturation_filter.h b/src/filters/hue_saturation_filter.h index 73a870f36..acc7888c2 100644 --- a/src/filters/hue_saturation_filter.h +++ b/src/filters/hue_saturation_filter.h @@ -17,8 +17,11 @@ namespace filters { class HueSaturationFilter : public Filter { public: + enum class Mode { HSL, HSV }; + HueSaturationFilter(); + void setMode(Mode mode); void setHue(double h); void setSaturation(double s); void setLightness(double v); @@ -32,8 +35,13 @@ namespace filters { private: void applyToPalette(FilterManager* filterMgr); - void applyHslFilterToRgb(const Target target, doc::color_t& color); + template + void applyFilterToRgbT(const Target target, doc::color_t& color); + void applyFilterToRgb(const Target target, doc::color_t& color); + Mode m_mode; double m_h, m_s, m_l, m_a; doc::PalettePicks m_picks; bool m_usePalette;