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

View File

@ -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<void>(&HueSaturationWindow::onChangeMode, this));
m_sliders.setColorType(app::Color::HslType);
m_sliders.setMode(ColorSliders::Mode::Relative);
m_sliders.ColorChange.connect(base::Bind<void>(&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;
};

View File

@ -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);

View File

@ -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<void(ColorSlidersChangeEvent&)> 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);

View File

@ -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 <cmath>
@ -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<class T,
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 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<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

View File

@ -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<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;
doc::PalettePicks m_picks;
bool m_usePalette;