Add support for HSV color space in Adjust Hue/Saturation (fix #1559)

This commit is contained in:
David Capello 2018-02-09 17:39:56 -03:00
parent c3a0c00a62
commit 166cb55c97
6 changed files with 131 additions and 19 deletions

View File

@ -93,6 +93,10 @@
<value id="LEFT" value="1" /> <value id="LEFT" value="1" />
<value id="RIGHT" value="2" /> <value id="RIGHT" value="2" />
</enum> </enum>
<enum id="HueSaturationMode">
<value id="HSV" value="0" />
<value id="HSL" value="1" />
</enum>
</types> </types>
<global> <global>
@ -261,6 +265,9 @@
<option id="show_alert" type="bool" default="true" /> <option id="show_alert" type="bool" default="true" />
<option id="quality" type="double" default="1.0" migrate="JPEG.Quality" /> <option id="quality" type="double" default="1.0" migrate="JPEG.Quality" />
</section> </section>
<section id="hue_saturation">
<option id="mode" type="HueSaturationMode" default="HueSaturationMode::HSL" />
</section>
</global> </global>
<tool> <tool>

View File

@ -15,6 +15,8 @@
#include "app/context.h" #include "app/context.h"
#include "app/ini_file.h" #include "app/ini_file.h"
#include "app/modules/gui.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_button.h"
#include "app/ui/color_sliders.h" #include "app/ui/color_sliders.h"
#include "base/bind.h" #include "base/bind.h"
@ -40,25 +42,70 @@ public:
WithChannelsSelector, WithChannelsSelector,
WithoutTiledCheckBox) WithoutTiledCheckBox)
, m_filter(filter) , m_filter(filter)
, m_colorType(2)
{ {
getContainer()->addChild(&m_colorType);
getContainer()->addChild(&m_sliders); 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<void>(&HueSaturationWindow::onChangeMode, this));
m_sliders.setColorType(app::Color::HslType); m_sliders.setColorType(app::Color::HslType);
m_sliders.setMode(ColorSliders::Mode::Relative); m_sliders.setMode(ColorSliders::Mode::Relative);
m_sliders.ColorChange.connect(base::Bind<void>(&HueSaturationWindow::onChangeControls, this)); m_sliders.ColorChange.connect(base::Bind<void>(&HueSaturationWindow::onChangeControls, this));
onChangeMode();
} }
private: 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() { void onChangeControls() {
m_sliders.syncRelHsvHslSliders();
if (isHsl()) {
m_filter.setHue( m_filter.setHue(
double(m_sliders.getRelSliderValue(ColorSliders::Channel::HslHue))); double(m_sliders.getRelSliderValue(ColorSliders::Channel::HslHue)));
m_filter.setSaturation( m_filter.setSaturation(
m_sliders.getRelSliderValue(ColorSliders::Channel::HslSaturation) / 100.0); m_sliders.getRelSliderValue(ColorSliders::Channel::HslSaturation) / 100.0);
m_filter.setLightness( m_filter.setLightness(
m_sliders.getRelSliderValue(ColorSliders::Channel::HslLightness) / 100.0); 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_filter.setAlpha(
m_sliders.getRelSliderValue(ColorSliders::Channel::Alpha) / 100.0); m_sliders.getRelSliderValue(ColorSliders::Channel::Alpha) / 100.0);
@ -66,6 +113,7 @@ private:
} }
HueSaturationFilter& m_filter; HueSaturationFilter& m_filter;
ButtonSet m_colorType;
ColorSliders m_sliders; ColorSliders m_sliders;
}; };

View File

@ -393,6 +393,12 @@ void ColorSliders::setAbsSliderValue(const Channel i, int value)
updateEntryText(i); 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 int ColorSliders::getAbsSliderValue(const Channel i) const
{ {
return m_items[i].absSlider->getValue(); return m_items[i].absSlider->getValue();
@ -403,6 +409,22 @@ int ColorSliders::getRelSliderValue(const Channel i) const
return m_items[i].relSlider->getValue(); 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) void ColorSliders::onSliderChange(const Channel i)
{ {
updateEntryText(i); updateEntryText(i);

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2018 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -46,6 +46,7 @@ namespace app {
int getAbsSliderValue(const Channel i) const; int getAbsSliderValue(const Channel i) const;
int getRelSliderValue(const Channel i) const; int getRelSliderValue(const Channel i) const;
void syncRelHsvHslSliders();
// Signals // Signals
obs::signal<void(ColorSlidersChangeEvent&)> ColorChange; obs::signal<void(ColorSlidersChangeEvent&)> ColorChange;
@ -59,6 +60,7 @@ namespace app {
const int absMin, const int absMax, const int absMin, const int absMax,
const int relMin, const int relMax); const int relMin, const int relMax);
void setAbsSliderValue(const Channel i, int value); void setAbsSliderValue(const Channel i, int value);
void setRelSliderValue(const Channel i, int value);
void updateSlidersVisibility(); void updateSlidersVisibility();
void onSetColor(const app::Color& color); void onSetColor(const app::Color& color);

View File

@ -16,6 +16,7 @@
#include "filters/filter_indexed_data.h" #include "filters/filter_indexed_data.h"
#include "filters/filter_manager.h" #include "filters/filter_manager.h"
#include "gfx/hsl.h" #include "gfx/hsl.h"
#include "gfx/hsv.h"
#include "gfx/rgb.h" #include "gfx/rgb.h"
#include <cmath> #include <cmath>
@ -30,13 +31,19 @@ const char* HueSaturationFilter::getName()
} }
HueSaturationFilter::HueSaturationFilter() HueSaturationFilter::HueSaturationFilter()
: m_h(0.0) : m_mode(Mode::HSL)
, m_h(0.0)
, m_s(0.0) , m_s(0.0)
, m_l(0.0) , m_l(0.0)
, m_a(0.0) , m_a(0.0)
{ {
} }
void HueSaturationFilter::setMode(Mode mode)
{
m_mode = mode;
}
void HueSaturationFilter::setHue(double h) void HueSaturationFilter::setHue(double h)
{ {
m_h = h; m_h = h;
@ -93,7 +100,7 @@ void HueSaturationFilter::applyToRgba(FilterManager* filterMgr)
c = fid->getNewPalette()->getEntry(i); c = fid->getNewPalette()->getEntry(i);
} }
else { else {
applyHslFilterToRgb(target, c); applyFilterToRgb(target, c);
} }
*(dst_address++) = c; *(dst_address++) = c;
@ -172,7 +179,7 @@ void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr)
} }
color_t c = pal->getEntry(*(src_address++)); color_t c = pal->getEntry(*(src_address++));
applyHslFilterToRgb(target, c); applyFilterToRgb(target, c);
*(dst_address++) = rgbmap->mapColor(rgba_getr(c), *(dst_address++) = rgbmap->mapColor(rgba_getr(c),
rgba_getg(c), rgba_getg(c),
rgba_getb(c), rgba_getb(c),
@ -195,21 +202,23 @@ void HueSaturationFilter::applyToPalette(FilterManager* filterMgr)
} }
color_t c = pal->getEntry(i); color_t c = pal->getEntry(i);
applyHslFilterToRgb(target, c); applyFilterToRgb(target, c);
newPal->setEntry(i, c); newPal->setEntry(i, c);
++i; ++i;
} }
} }
void HueSaturationFilter::applyHslFilterToRgb( template<class T,
const Target target, doc::color_t& c) double (T::*get_lightness)() const,
void (T::*set_lightness)(double)>
void HueSaturationFilter::applyFilterToRgbT(const Target target, doc::color_t& c)
{ {
int r = rgba_getr(c); int r = rgba_getr(c);
int g = rgba_getg(c); int g = rgba_getg(c);
int b = rgba_getb(c); int b = rgba_getb(c);
int a = rgba_geta(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; double h = hsl.hue() + m_h;
while (h < 0.0) h += 360.0; while (h < 0.0) h += 360.0;
@ -218,12 +227,12 @@ void HueSaturationFilter::applyHslFilterToRgb(
double s = hsl.saturation()*(1.0+m_s); double s = hsl.saturation()*(1.0+m_s);
s = MID(0.0, s, 1.0); 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); l = MID(0.0, l, 1.0);
hsl.hue(h); hsl.hue(h);
hsl.saturation(s); hsl.saturation(s);
hsl.lightness(l); (hsl.*set_lightness)(l);
gfx::Rgb rgb(hsl); gfx::Rgb rgb(hsl);
if (target & TARGET_RED_CHANNEL ) r = rgb.red(); if (target & TARGET_RED_CHANNEL ) r = rgb.red();
@ -237,4 +246,20 @@ void HueSaturationFilter::applyHslFilterToRgb(
c = rgba(r, g, b, a); c = rgba(r, g, b, a);
} }
void HueSaturationFilter::applyFilterToRgb(const Target target, doc::color_t& color)
{
switch (m_mode) {
case Mode::HSL:
applyFilterToRgbT<gfx::Hsl,
&gfx::Hsl::lightness,
&gfx::Hsl::lightness>(target, color);
break;
case Mode::HSV:
applyFilterToRgbT<gfx::Hsv,
&gfx::Hsv::value,
&gfx::Hsv::value>(target, color);
break;
}
}
} // namespace filters } // namespace filters

View File

@ -17,8 +17,11 @@ namespace filters {
class HueSaturationFilter : public Filter { class HueSaturationFilter : public Filter {
public: public:
enum class Mode { HSL, HSV };
HueSaturationFilter(); HueSaturationFilter();
void setMode(Mode mode);
void setHue(double h); void setHue(double h);
void setSaturation(double s); void setSaturation(double s);
void setLightness(double v); void setLightness(double v);
@ -32,8 +35,13 @@ namespace filters {
private: private:
void applyToPalette(FilterManager* filterMgr); void applyToPalette(FilterManager* filterMgr);
void applyHslFilterToRgb(const Target target, doc::color_t& color); template<class T,
double (T::*get_lightness)() const,
void (T::*set_lightness)(double)>
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; double m_h, m_s, m_l, m_a;
doc::PalettePicks m_picks; doc::PalettePicks m_picks;
bool m_usePalette; bool m_usePalette;