mirror of https://github.com/aseprite/aseprite.git
Add support for HSV color space in Adjust Hue/Saturation (fix #1559)
This commit is contained in:
parent
c3a0c00a62
commit
166cb55c97
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue