Add HSL color selection (related to #707)

This commit is contained in:
David Capello 2017-05-29 14:20:42 -03:00
parent c297031152
commit 29a49ad7fa
24 changed files with 640 additions and 241 deletions

View File

@ -50,9 +50,11 @@
<value id="RGB" value="4" /> <value id="RGB" value="4" />
<value id="HSVA" value="5" /> <value id="HSVA" value="5" />
<value id="HSV" value="6" /> <value id="HSV" value="6" />
<value id="GRAYA" value="7" /> <value id="HSLA" value="7" />
<value id="GRAY" value="8" /> <value id="HSL" value="8" />
<value id="INDEX" value="9" /> <value id="GRAYA" value="9" />
<value id="GRAY" value="10" />
<value id="INDEX" value="11" />
</enum> </enum>
<enum id="EyedropperSample"> <enum id="EyedropperSample">
<value id="ALL_LAYERS" value="0" /> <value id="ALL_LAYERS" value="0" />

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2017 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.
@ -12,11 +12,12 @@
#include "app/color_utils.h" #include "app/color_utils.h"
#include "app/modules/palettes.h" #include "app/modules/palettes.h"
#include "gfx/hsv.h"
#include "gfx/rgb.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/palette.h" #include "doc/palette.h"
#include "doc/primitives.h" #include "doc/primitives.h"
#include "gfx/hsl.h"
#include "gfx/hsv.h"
#include "gfx/rgb.h"
#include <cmath> #include <cmath>
#include <cstdlib> #include <cstdlib>
@ -56,6 +57,17 @@ Color Color::fromHsv(double h, double s, double v, int a)
return color; return color;
} }
// static
Color Color::fromHsl(double h, double s, double l, int a)
{
Color color(Color::HslType);
color.m_value.hsl.h = h;
color.m_value.hsl.s = s;
color.m_value.hsl.l = l;
color.m_value.hsl.a = a;
return color;
}
// static // static
Color Color::fromGray(int g, int a) Color Color::fromGray(int g, int a)
{ {
@ -123,6 +135,7 @@ Color Color::fromString(const std::string& str)
if (str != "mask") { if (str != "mask") {
if (str.find("rgb{") == 0 || if (str.find("rgb{") == 0 ||
str.find("hsv{") == 0 || str.find("hsv{") == 0 ||
str.find("hsl{") == 0 ||
str.find("gray{") == 0) { str.find("gray{") == 0) {
int c = 0; int c = 0;
double table[4] = { 0.0, 0.0, 0.0, 255.0 }; double table[4] = { 0.0, 0.0, 0.0, 255.0 };
@ -139,8 +152,16 @@ Color Color::fromString(const std::string& str)
if (str[0] == 'r') if (str[0] == 'r')
color = Color::fromRgb(int(table[0]), int(table[1]), int(table[2]), int(table[3])); color = Color::fromRgb(int(table[0]), int(table[1]), int(table[2]), int(table[3]));
else if (str[0] == 'h') else if (str[0] == 'h' && str[1] == 's' && str[2] == 'v')
color = Color::fromHsv(table[0], table[1], table[2], int(table[3])); color = Color::fromHsv(table[0],
table[1] / 100.0,
table[2] / 100.0,
int(table[3]));
else if (str[0] == 'h' && str[1] == 's' && str[2] == 'l')
color = Color::fromHsl(table[0],
table[1] / 100.0,
table[2] / 100.0,
int(table[3]));
else if (str[0] == 'g') else if (str[0] == 'g')
color = Color::fromGray(int(table[0]), (c >= 2 ? int(table[1]): 255)); color = Color::fromGray(int(table[0]), (c >= 2 ? int(table[1]): 255));
} }
@ -175,11 +196,21 @@ std::string Color::toString() const
<< std::setprecision(2) << std::setprecision(2)
<< std::fixed << std::fixed
<< m_value.hsv.h << "," << m_value.hsv.h << ","
<< m_value.hsv.s << "," << MID(0.0, m_value.hsv.s*100.0, 100.0) << ","
<< m_value.hsv.v << "," << MID(0.0, m_value.hsv.v*100.0, 100.0) << ","
<< m_value.hsv.a << "}"; << m_value.hsv.a << "}";
break; break;
case Color::HslType:
result << "hsl{"
<< std::setprecision(2)
<< std::fixed
<< m_value.hsl.h << ","
<< MID(0.0, m_value.hsl.s*100.0, 100.0) << ","
<< MID(0.0, m_value.hsl.l*100.0, 100.0) << ","
<< m_value.hsl.a << "}";
break;
case Color::GrayType: case Color::GrayType:
result << "gray{" result << "gray{"
<< m_value.gray.g << "," << m_value.gray.g << ","
@ -227,10 +258,30 @@ std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableS
result << "Gray " << getGray(); result << "Gray " << getGray();
} }
else { else {
result << "HSB " result << "HSV "
<< int(m_value.hsv.h) << "\xc2\xb0 " << int(m_value.hsv.h) << "\xc2\xb0 "
<< int(m_value.hsv.s) << "% " << MID(0, int(m_value.hsv.s*100.0), 100) << "% "
<< int(m_value.hsv.v) << "%"; << MID(0, int(m_value.hsv.v*100.0), 100) << "%";
if (pixelFormat == IMAGE_INDEXED)
result << " Index " << color_utils::color_for_image(*this, pixelFormat);
result << " (RGB "
<< getRed() << " "
<< getGreen() << " "
<< getBlue() << ")";
}
break;
case Color::HslType:
if (pixelFormat == IMAGE_GRAYSCALE) {
result << "Gray " << getGray();
}
else {
result << "HSL "
<< int(m_value.hsl.h) << "\xc2\xb0 "
<< MID(0, int(m_value.hsl.s*100.0), 100) << "% "
<< MID(0, int(m_value.hsl.l*100.0), 100) << "%";
if (pixelFormat == IMAGE_INDEXED) if (pixelFormat == IMAGE_INDEXED)
result << " Index " << color_utils::color_for_image(*this, pixelFormat); result << " Index " << color_utils::color_for_image(*this, pixelFormat);
@ -299,8 +350,19 @@ std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableS
} }
else { else {
result << int(m_value.hsv.h) << "\xc2\xb0" result << int(m_value.hsv.h) << "\xc2\xb0"
<< int(m_value.hsv.s) << "," << MID(0, int(m_value.hsv.s*100.0), 100) << ","
<< int(m_value.hsv.v); << MID(0, int(m_value.hsv.v*100.0), 100);
}
break;
case Color::HslType:
if (pixelFormat == IMAGE_GRAYSCALE) {
result << "Gry-" << getGray();
}
else {
result << int(m_value.hsl.h) << "\xc2\xb0"
<< MID(0, int(m_value.hsl.s*100.0), 100) << ","
<< MID(0, int(m_value.hsl.l*100.0), 100);
} }
break; break;
@ -341,10 +403,17 @@ bool Color::operator==(const Color& other) const
case Color::HsvType: case Color::HsvType:
return return
(std::fabs(m_value.hsv.h - other.m_value.hsv.h) < 0.001) && (std::fabs(m_value.hsv.h - other.m_value.hsv.h) < 0.001) &&
(std::fabs(m_value.hsv.s - other.m_value.hsv.s) < 0.001) && (std::fabs(m_value.hsv.s - other.m_value.hsv.s) < 0.00001) &&
(std::fabs(m_value.hsv.v - other.m_value.hsv.v) < 0.001) && (std::fabs(m_value.hsv.v - other.m_value.hsv.v) < 0.00001) &&
(m_value.hsv.a == other.m_value.hsv.a); (m_value.hsv.a == other.m_value.hsv.a);
case Color::HslType:
return
(std::fabs(m_value.hsl.h - other.m_value.hsl.h) < 0.001) &&
(std::fabs(m_value.hsl.s - other.m_value.hsl.s) < 0.00001) &&
(std::fabs(m_value.hsl.l - other.m_value.hsl.l) < 0.00001) &&
(m_value.hsl.a == other.m_value.hsl.a);
case Color::GrayType: case Color::GrayType:
return return
m_value.gray.g == other.m_value.gray.g && m_value.gray.g == other.m_value.gray.g &&
@ -387,8 +456,13 @@ int Color::getRed() const
case Color::HsvType: case Color::HsvType:
return Rgb(Hsv(m_value.hsv.h, return Rgb(Hsv(m_value.hsv.h,
m_value.hsv.s / 100.0, m_value.hsv.s,
m_value.hsv.v / 100.0)).red(); m_value.hsv.v)).red();
case Color::HslType:
return Rgb(Hsl(m_value.hsl.h,
m_value.hsl.s,
m_value.hsl.l)).red();
case Color::GrayType: case Color::GrayType:
return m_value.gray.g; return m_value.gray.g;
@ -419,8 +493,13 @@ int Color::getGreen() const
case Color::HsvType: case Color::HsvType:
return Rgb(Hsv(m_value.hsv.h, return Rgb(Hsv(m_value.hsv.h,
m_value.hsv.s / 100.0, m_value.hsv.s,
m_value.hsv.v / 100.0)).green(); m_value.hsv.v)).green();
case Color::HslType:
return Rgb(Hsl(m_value.hsl.h,
m_value.hsl.s,
m_value.hsl.l)).green();
case Color::GrayType: case Color::GrayType:
return m_value.gray.g; return m_value.gray.g;
@ -451,8 +530,13 @@ int Color::getBlue() const
case Color::HsvType: case Color::HsvType:
return Rgb(Hsv(m_value.hsv.h, return Rgb(Hsv(m_value.hsv.h,
m_value.hsv.s / 100.0, m_value.hsv.s,
m_value.hsv.v / 100.0)).blue(); m_value.hsv.v)).blue();
case Color::HslType:
return Rgb(Hsl(m_value.hsl.h,
m_value.hsl.s,
m_value.hsl.l)).blue();
case Color::GrayType: case Color::GrayType:
return m_value.gray.g; return m_value.gray.g;
@ -471,7 +555,7 @@ int Color::getBlue() const
return -1; return -1;
} }
double Color::getHue() const double Color::getHsvHue() const
{ {
switch (getType()) { switch (getType()) {
@ -486,6 +570,9 @@ double Color::getHue() const
case Color::HsvType: case Color::HsvType:
return m_value.hsv.h; return m_value.hsv.h;
case Color::HslType:
return m_value.hsl.h;
case Color::GrayType: case Color::GrayType:
return 0.0; return 0.0;
@ -507,7 +594,7 @@ double Color::getHue() const
return -1.0; return -1.0;
} }
double Color::getSaturation() const double Color::getHsvSaturation() const
{ {
switch (getType()) { switch (getType()) {
@ -517,11 +604,16 @@ double Color::getSaturation() const
case Color::RgbType: case Color::RgbType:
return Hsv(Rgb(m_value.rgb.r, return Hsv(Rgb(m_value.rgb.r,
m_value.rgb.g, m_value.rgb.g,
m_value.rgb.b)).saturation() * 100.0; m_value.rgb.b)).saturation();
case Color::HsvType: case Color::HsvType:
return m_value.hsv.s; return m_value.hsv.s;
case Color::HslType:
return Hsv(Rgb(getRed(),
getGreen(),
getBlue())).saturation();
case Color::GrayType: case Color::GrayType:
return 0; return 0;
@ -531,7 +623,7 @@ double Color::getSaturation() const
uint32_t c = get_current_palette()->getEntry(i); uint32_t c = get_current_palette()->getEntry(i);
return Hsv(Rgb(rgba_getr(c), return Hsv(Rgb(rgba_getr(c),
rgba_getg(c), rgba_getg(c),
rgba_getb(c))).saturation() * 100.0; rgba_getb(c))).saturation();
} }
else else
return 0.0; return 0.0;
@ -543,7 +635,7 @@ double Color::getSaturation() const
return -1.0; return -1.0;
} }
double Color::getValue() const double Color::getHsvValue() const
{ {
switch (getType()) { switch (getType()) {
@ -553,13 +645,18 @@ double Color::getValue() const
case Color::RgbType: case Color::RgbType:
return Hsv(Rgb(m_value.rgb.r, return Hsv(Rgb(m_value.rgb.r,
m_value.rgb.g, m_value.rgb.g,
m_value.rgb.b)).value() * 100.0; m_value.rgb.b)).value();
case Color::HsvType: case Color::HsvType:
return m_value.hsv.v; return m_value.hsv.v;
case Color::HslType:
return Hsv(Rgb(getRed(),
getGreen(),
getBlue())).value();
case Color::GrayType: case Color::GrayType:
return 100.0 * m_value.gray.g / 255.0; return m_value.gray.g / 255.0;
case Color::IndexType: { case Color::IndexType: {
int i = m_value.index; int i = m_value.index;
@ -567,7 +664,128 @@ double Color::getValue() const
uint32_t c = get_current_palette()->getEntry(i); uint32_t c = get_current_palette()->getEntry(i);
return Hsv(Rgb(rgba_getr(c), return Hsv(Rgb(rgba_getr(c),
rgba_getg(c), rgba_getg(c),
rgba_getb(c))).value() * 100.0; rgba_getb(c))).value();
}
else
return 0.0;
}
}
ASSERT(false);
return -1.0;
}
double Color::getHslHue() const
{
switch (getType()) {
case Color::MaskType:
return 0.0;
case Color::RgbType:
return Hsl(Rgb(m_value.rgb.r,
m_value.rgb.g,
m_value.rgb.b)).hue();
case Color::HsvType:
return m_value.hsv.h;
case Color::HslType:
return m_value.hsl.h;
case Color::GrayType:
return 0.0;
case Color::IndexType: {
int i = m_value.index;
if (i >= 0 && i < get_current_palette()->size()) {
uint32_t c = get_current_palette()->getEntry(i);
return Hsl(Rgb(rgba_getr(c),
rgba_getg(c),
rgba_getb(c))).hue();
}
else
return 0.0;
}
}
ASSERT(false);
return -1.0;
}
double Color::getHslSaturation() const
{
switch (getType()) {
case Color::MaskType:
return 0;
case Color::RgbType:
return Hsl(Rgb(m_value.rgb.r,
m_value.rgb.g,
m_value.rgb.b)).saturation();
case Color::HsvType:
return Hsl(Rgb(getRed(),
getGreen(),
getBlue())).saturation();
case Color::HslType:
return m_value.hsl.s;
case Color::GrayType:
return 0;
case Color::IndexType: {
int i = m_value.index;
if (i >= 0 && i < get_current_palette()->size()) {
uint32_t c = get_current_palette()->getEntry(i);
return Hsl(Rgb(rgba_getr(c),
rgba_getg(c),
rgba_getb(c))).saturation();
}
else
return 0.0;
}
}
ASSERT(false);
return -1.0;
}
double Color::getHslLightness() const
{
switch (getType()) {
case Color::MaskType:
return 0.0;
case Color::RgbType:
return Hsl(Rgb(m_value.rgb.r,
m_value.rgb.g,
m_value.rgb.b)).lightness();
case Color::HsvType:
return Hsl(Rgb(getRed(),
getGreen(),
getBlue())).lightness();
case Color::HslType:
return m_value.hsl.l;
case Color::GrayType:
return m_value.gray.g / 255.0;
case Color::IndexType: {
int i = m_value.index;
if (i >= 0 && i < get_current_palette()->size()) {
uint32_t c = get_current_palette()->getEntry(i);
return Hsl(Rgb(rgba_getr(c),
rgba_getg(c),
rgba_getb(c))).lightness();
} }
else else
return 0.0; return 0.0;
@ -587,12 +805,17 @@ int Color::getGray() const
return 0; return 0;
case Color::RgbType: case Color::RgbType:
return int(255.0 * Hsv(Rgb(m_value.rgb.r, return int(255.0 * Hsl(Rgb(m_value.rgb.r,
m_value.rgb.g, m_value.rgb.g,
m_value.rgb.b)).value()); m_value.rgb.b)).lightness());
case Color::HsvType: case Color::HsvType:
return int(255.0 * m_value.hsv.v / 100.0); return int(255.0 * Hsl(Rgb(getRed(),
getGreen(),
getBlue())).lightness());
case Color::HslType:
return int(255.0 * m_value.hsl.l);
case Color::GrayType: case Color::GrayType:
return m_value.gray.g; return m_value.gray.g;
@ -601,9 +824,9 @@ int Color::getGray() const
int i = m_value.index; int i = m_value.index;
if (i >= 0 && i < get_current_palette()->size()) { if (i >= 0 && i < get_current_palette()->size()) {
uint32_t c = get_current_palette()->getEntry(i); uint32_t c = get_current_palette()->getEntry(i);
return int(255.0 * Hsv(Rgb(rgba_getr(c), return int(255.0 * Hsl(Rgb(rgba_getr(c),
rgba_getg(c), rgba_getg(c),
rgba_getb(c))).value()); rgba_getb(c))).lightness());
} }
else else
return 0; return 0;
@ -624,6 +847,7 @@ int Color::getIndex() const
case Color::RgbType: case Color::RgbType:
case Color::HsvType: case Color::HsvType:
case Color::HslType:
case Color::GrayType: { case Color::GrayType: {
int i = get_current_palette()->findExactMatch(getRed(), getGreen(), getBlue(), getAlpha(), -1); int i = get_current_palette()->findExactMatch(getRed(), getGreen(), getBlue(), getAlpha(), -1);
if (i >= 0) if (i >= 0)
@ -654,6 +878,9 @@ int Color::getAlpha() const
case Color::HsvType: case Color::HsvType:
return m_value.hsv.a; return m_value.hsv.a;
case Color::HslType:
return m_value.hsl.a;
case Color::GrayType: case Color::GrayType:
return m_value.gray.a; return m_value.gray.a;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2017 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.
@ -28,6 +28,7 @@ namespace app {
MaskType, MaskType,
RgbType, RgbType,
HsvType, HsvType,
HslType,
GrayType, GrayType,
IndexType, IndexType,
}; };
@ -42,7 +43,8 @@ namespace app {
static Color fromMask(); static Color fromMask();
static Color fromRgb(int r, int g, int b, int a = 255); static Color fromRgb(int r, int g, int b, int a = 255);
static Color fromHsv(double h, double s, double v, int a = 255); // h=[0,360], s=[0,100], v=[0,100] static Color fromHsv(double h, double s, double v, int a = 255); // h=[0,360], s=[0,1], v=[0,1]
static Color fromHsl(double h, double s, double l, int a = 255); // h=[0,360], s=[0,1], v=[0,1]
static Color fromGray(int g, int a = 255); static Color fromGray(int g, int a = 255);
static Color fromIndex(int index); static Color fromIndex(int index);
@ -68,9 +70,12 @@ namespace app {
int getRed() const; int getRed() const;
int getGreen() const; int getGreen() const;
int getBlue() const; int getBlue() const;
double getHue() const; double getHsvHue() const;
double getSaturation() const; double getHsvSaturation() const;
double getValue() const; double getHsvValue() const;
double getHslHue() const;
double getHslSaturation() const;
double getHslLightness() const;
int getGray() const; int getGray() const;
int getIndex() const; int getIndex() const;
int getAlpha() const; int getAlpha() const;
@ -90,6 +95,10 @@ namespace app {
double h, s, v; double h, s, v;
int a; int a;
} hsv; } hsv;
struct {
double h, s, l;
int a;
} hsl;
struct { struct {
int g, a; int g, a;
} gray; } gray;

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2017 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.
@ -20,28 +20,37 @@ namespace app {
TEST(Color, fromRgb) TEST(Color, fromRgb)
{ {
EXPECT_EQ(32, Color::fromRgb(32, 16, 255).getRed()); EXPECT_EQ( 32, Color::fromRgb(32, 16, 255).getRed());
EXPECT_EQ(16, Color::fromRgb(32, 16, 255).getGreen()); EXPECT_EQ( 16, Color::fromRgb(32, 16, 255).getGreen());
EXPECT_EQ(255, Color::fromRgb(32, 16, 255).getBlue()); EXPECT_EQ(255, Color::fromRgb(32, 16, 255).getBlue());
} }
TEST(Color, fromHsv) TEST(Color, fromHsv)
{ {
EXPECT_EQ(60, Color::fromHsv(60, 5, 100).getHue()); EXPECT_EQ(60.0, Color::fromHsv(60, 0.05, 1.0).getHsvHue());
EXPECT_EQ(5, Color::fromHsv(60, 5, 100).getSaturation()); EXPECT_EQ(0.05, Color::fromHsv(60, 0.05, 1.0).getHsvSaturation());
EXPECT_EQ(100, Color::fromHsv(60, 5, 100).getValue()); EXPECT_EQ(1.00, Color::fromHsv(60, 0.05, 1.0).getHsvValue());
}
TEST(Color, fromHsl)
{
EXPECT_EQ(60.0, Color::fromHsl(60, 0.05, 1.0).getHslHue());
EXPECT_EQ(0.05, Color::fromHsl(60, 0.05, 1.0).getHslSaturation());
EXPECT_EQ(1.00, Color::fromHsl(60, 0.05, 1.0).getHslLightness());
} }
TEST(Color, fromString) TEST(Color, fromString)
{ {
EXPECT_EQ(Color::fromRgb(0, 0, 0), Color::fromString("rgb{0,0.0,0}")); EXPECT_EQ(Color::fromRgb(0, 0, 0), Color::fromString("rgb{0,0.0,0}"));
EXPECT_EQ(Color::fromRgb(32, 16, 255), Color::fromString("rgb{32,16,255}")); EXPECT_EQ(Color::fromRgb(32, 16, 255), Color::fromString("rgb{32,16,255}"));
EXPECT_EQ(Color::fromHsv(32, 64, 99), Color::fromString("hsv{32,64,99}")); EXPECT_EQ(Color::fromHsv(32, 0.64, 0.99), Color::fromString("hsv{32,64,99}"));
EXPECT_EQ(Color::fromHsl(32, 0.64, 0.99), Color::fromString("hsl{32,64,99}"));
} }
TEST(Color, toString) TEST(Color, toString)
{ {
EXPECT_EQ("rgb{0,0,0,255}", Color::fromRgb(0, 0, 0).toString()); EXPECT_EQ("rgb{0,0,0,255}", Color::fromRgb(0, 0, 0).toString());
EXPECT_EQ("rgb{32,16,255,255}", Color::fromRgb(32, 16, 255).toString()); EXPECT_EQ("rgb{32,16,255,255}", Color::fromRgb(32, 16, 255).toString());
EXPECT_EQ("hsv{32.00,64.00,99.00,255}", Color::fromHsv(32, 64, 99).toString()); EXPECT_EQ("hsv{32.00,64.00,99.00,255}", Color::fromHsv(32, 64/100.0, 99/100.0).toString());
EXPECT_EQ("hsl{32.00,64.00,99.00,255}", Color::fromHsl(32, 64/100.0, 99/100.0).toString());
} }

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2017 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.
@ -48,6 +48,7 @@ gfx::Color color_utils::color_for_ui(const app::Color& color)
case app::Color::RgbType: case app::Color::RgbType:
case app::Color::HsvType: case app::Color::HsvType:
case app::Color::HslType:
c = gfx::rgba( c = gfx::rgba(
color.getRed(), color.getRed(),
color.getGreen(), color.getGreen(),

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2017 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.
@ -90,9 +90,16 @@ void EyedropperCommand::pickSample(const doc::Site& site,
break; break;
case app::Color::HsvType: case app::Color::HsvType:
color = app::Color::fromHsv(color.getHue(), color = app::Color::fromHsv(color.getHsvHue(),
color.getSaturation(), color.getHsvSaturation(),
color.getValue(), color.getHsvValue(),
picked.getAlpha());
break;
case app::Color::HslType:
color = app::Color::fromHsl(color.getHslHue(),
color.getHslSaturation(),
color.getHslLightness(),
picked.getAlpha()); picked.getAlpha());
break; break;
@ -123,16 +130,32 @@ void EyedropperCommand::pickSample(const doc::Site& site,
if (picked.getType() == app::Color::HsvType) if (picked.getType() == app::Color::HsvType)
color = picked; color = picked;
else else
color = app::Color::fromHsv(picked.getHue(), color = app::Color::fromHsv(picked.getHsvHue(),
picked.getSaturation(), picked.getHsvSaturation(),
picked.getValue(), picked.getHsvValue(),
picked.getAlpha()); picked.getAlpha());
break; break;
case app::gen::EyedropperChannel::HSV: case app::gen::EyedropperChannel::HSV:
if (picked.getAlpha() > 0) if (picked.getAlpha() > 0)
color = app::Color::fromHsv(picked.getHue(), color = app::Color::fromHsv(picked.getHsvHue(),
picked.getSaturation(), picked.getHsvSaturation(),
picked.getValue(), picked.getHsvValue(),
color.getAlpha());
break;
case app::gen::EyedropperChannel::HSLA:
if (picked.getType() == app::Color::HslType)
color = picked;
else
color = app::Color::fromHsl(picked.getHslHue(),
picked.getHslSaturation(),
picked.getHslLightness(),
picked.getAlpha());
break;
case app::gen::EyedropperChannel::HSL:
if (picked.getAlpha() > 0)
color = app::Color::fromHsl(picked.getHslHue(),
picked.getHslSaturation(),
picked.getHslLightness(),
color.getAlpha()); color.getAlpha());
break; break;
case app::gen::EyedropperChannel::GRAYA: case app::gen::EyedropperChannel::GRAYA:

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2017 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.
@ -39,6 +39,7 @@
#include "doc/image.h" #include "doc/image.h"
#include "doc/palette.h" #include "doc/palette.h"
#include "doc/sprite.h" #include "doc/sprite.h"
#include "gfx/hsl.h"
#include "gfx/hsv.h" #include "gfx/hsv.h"
#include "gfx/rgb.h" #include "gfx/rgb.h"
#include "gfx/size.h" #include "gfx/size.h"
@ -54,7 +55,7 @@ namespace app {
using namespace gfx; using namespace gfx;
using namespace ui; using namespace ui;
enum { RGB_MODE, HSV_MODE }; enum { RGB_MODE, HSV_MODE, HSL_MODE };
enum { ABS_MODE, REL_MODE }; enum { ABS_MODE, REL_MODE };
class PaletteEntryEditor : public Window { class PaletteEntryEditor : public Window {
@ -97,6 +98,7 @@ private:
Label m_entryLabel; Label m_entryLabel;
RgbSliders m_rgbSliders; RgbSliders m_rgbSliders;
HsvSliders m_hsvSliders; HsvSliders m_hsvSliders;
HslSliders m_hslSliders;
// This variable is used to avoid updating the m_hexColorEntry text // This variable is used to avoid updating the m_hexColorEntry text
// when the color change is generated from a // when the color change is generated from a
@ -241,7 +243,7 @@ PaletteEntryEditor::PaletteEntryEditor()
, m_vbox(VERTICAL) , m_vbox(VERTICAL)
, m_topBox(HORIZONTAL) , m_topBox(HORIZONTAL)
, m_bottomBox(HORIZONTAL) , m_bottomBox(HORIZONTAL)
, m_colorType(2) , m_colorType(3)
, m_changeMode(2) , m_changeMode(2)
, m_entryLabel("") , m_entryLabel("")
, m_disableHexUpdate(false) , m_disableHexUpdate(false)
@ -252,7 +254,8 @@ PaletteEntryEditor::PaletteEntryEditor()
, m_fromPalette(0, 0) , m_fromPalette(0, 0)
{ {
m_colorType.addItem("RGB")->setFocusStop(false); m_colorType.addItem("RGB")->setFocusStop(false);
m_colorType.addItem("HSB")->setFocusStop(false); m_colorType.addItem("HSV")->setFocusStop(false);
m_colorType.addItem("HSL")->setFocusStop(false);
m_changeMode.addItem("Abs")->setFocusStop(false); m_changeMode.addItem("Abs")->setFocusStop(false);
m_changeMode.addItem("Rel")->setFocusStop(false); m_changeMode.addItem("Rel")->setFocusStop(false);
@ -273,6 +276,7 @@ PaletteEntryEditor::PaletteEntryEditor()
m_vbox.addChild(&m_topBox); m_vbox.addChild(&m_topBox);
m_vbox.addChild(&m_rgbSliders); m_vbox.addChild(&m_rgbSliders);
m_vbox.addChild(&m_hsvSliders); m_vbox.addChild(&m_hsvSliders);
m_vbox.addChild(&m_hslSliders);
m_vbox.addChild(&m_bottomBox); m_vbox.addChild(&m_bottomBox);
addChild(&m_vbox); addChild(&m_vbox);
@ -281,6 +285,7 @@ PaletteEntryEditor::PaletteEntryEditor()
m_rgbSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this); m_rgbSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_hsvSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this); m_hsvSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_hslSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_hexColorEntry.ColorChange.connect(&PaletteEntryEditor::onColorHexEntryChange, this); m_hexColorEntry.ColorChange.connect(&PaletteEntryEditor::onColorHexEntryChange, this);
m_changeMode.setSelectedItem(ABS_MODE); m_changeMode.setSelectedItem(ABS_MODE);
@ -309,6 +314,7 @@ void PaletteEntryEditor::setColor(const app::Color& color)
{ {
m_rgbSliders.setColor(color); m_rgbSliders.setColor(color);
m_hsvSliders.setColor(color); m_hsvSliders.setColor(color);
m_hslSliders.setColor(color);
if (!m_disableHexUpdate) if (!m_disableHexUpdate)
m_hexColorEntry.setColor(color); m_hexColorEntry.setColor(color);
@ -455,6 +461,9 @@ void PaletteEntryEditor::onColorTypeClick()
case HSV_MODE: case HSV_MODE:
selectColorType(app::Color::HsvType); selectColorType(app::Color::HsvType);
break; break;
case HSL_MODE:
selectColorType(app::Color::HslType);
break;
} }
} }
@ -464,10 +473,12 @@ void PaletteEntryEditor::onChangeModeClick()
case ABS_MODE: case ABS_MODE:
m_rgbSliders.setMode(ColorSliders::Absolute); m_rgbSliders.setMode(ColorSliders::Absolute);
m_hsvSliders.setMode(ColorSliders::Absolute); m_hsvSliders.setMode(ColorSliders::Absolute);
m_hslSliders.setMode(ColorSliders::Absolute);
break; break;
case REL_MODE: case REL_MODE:
m_rgbSliders.setMode(ColorSliders::Relative); m_rgbSliders.setMode(ColorSliders::Relative);
m_hsvSliders.setMode(ColorSliders::Relative); m_hsvSliders.setMode(ColorSliders::Relative);
m_hslSliders.setMode(ColorSliders::Relative);
break; break;
} }
@ -541,46 +552,86 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
} }
break; break;
case app::Color::HsvType: case app::Color::HsvType: {
{ Hsv hsv;
Hsv hsv;
// Modify one entry // Modify one entry
if (picksCount == 1) { if (picksCount == 1) {
hsv.hue(color.getHue()); hsv.hue(color.getHsvHue());
hsv.saturation(double(color.getSaturation()) / 100.0); hsv.saturation(color.getHsvSaturation());
hsv.value(double(color.getValue()) / 100.0); hsv.value(color.getHsvValue());
a = color.getAlpha(); a = color.getAlpha();
}
// Modify one channel a set of entries
else {
// Convert RGB to HSV
hsv = Hsv(Rgb(r, g, b));
// Only modify the desired HSV channel
switch (channel) {
case ColorSliders::Hue:
hsv.hue(color.getHue());
break;
case ColorSliders::Saturation:
hsv.saturation(double(color.getSaturation()) / 100.0);
break;
case ColorSliders::Value:
hsv.value(double(color.getValue()) / 100.0);
break;
case ColorSliders::Alpha:
a = color.getAlpha();
break;
}
}
// Convert HSV back to RGB
Rgb rgb(hsv);
r = rgb.red();
g = rgb.green();
b = rgb.blue();
} }
// Modify one channel a set of entries
else {
// Convert RGB to HSV
hsv = Hsv(Rgb(r, g, b));
// Only modify the desired HSV channel
switch (channel) {
case ColorSliders::HsvHue:
hsv.hue(color.getHsvHue());
break;
case ColorSliders::HsvSaturation:
hsv.saturation(color.getHsvSaturation());
break;
case ColorSliders::HsvValue:
hsv.value(color.getHsvValue());
break;
case ColorSliders::Alpha:
a = color.getAlpha();
break;
}
}
// Convert HSV back to RGB
Rgb rgb(hsv);
r = rgb.red();
g = rgb.green();
b = rgb.blue();
break; break;
}
case app::Color::HslType: {
Hsl hsl;
// Modify one entry
if (picksCount == 1) {
hsl.hue(color.getHslHue());
hsl.saturation(color.getHslSaturation());
hsl.lightness(color.getHslLightness());
a = color.getAlpha();
}
// Modify one channel a set of entries
else {
// Convert RGB to HSL
hsl = Hsl(Rgb(r, g, b));
// Only modify the desired HSL channel
switch (channel) {
case ColorSliders::HslHue:
hsl.hue(color.getHslHue());
break;
case ColorSliders::HslSaturation:
hsl.saturation(color.getHslSaturation());
break;
case ColorSliders::HslLightness:
hsl.lightness(color.getHslLightness());
break;
case ColorSliders::Alpha:
a = color.getAlpha();
break;
}
}
// Convert HSL back to RGB
Rgb rgb(hsl);
r = rgb.red();
g = rgb.green();
b = rgb.blue();
break;
}
} }
palette->setEntry(c, doc::rgba(r, g, b, a)); palette->setEntry(c, doc::rgba(r, g, b, a));
@ -613,9 +664,9 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
switch (m_type) { switch (m_type) {
case app::Color::RgbType: case app::Color::RgbType:
r = MID(0, r+m_relDeltas[ColorSliders::Red], 255); r = MID(0, r+m_relDeltas[ColorSliders::Red], 255);
g = MID(0, g+m_relDeltas[ColorSliders::Green], 255); g = MID(0, g+m_relDeltas[ColorSliders::Green], 255);
b = MID(0, b+m_relDeltas[ColorSliders::Blue], 255); b = MID(0, b+m_relDeltas[ColorSliders::Blue], 255);
a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255); a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255);
break; break;
@ -623,16 +674,16 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
// Convert RGB to HSV // Convert RGB to HSV
Hsv hsv(Rgb(r, g, b)); Hsv hsv(Rgb(r, g, b));
double h = hsv.hue()+m_relDeltas[ColorSliders::Hue]; double h = hsv.hue() +m_relDeltas[ColorSliders::HsvHue];
double s = 100.0*hsv.saturation()+m_relDeltas[ColorSliders::Saturation]; double s = hsv.saturation()+m_relDeltas[ColorSliders::HsvSaturation]/100.0;
double v = 100.0*hsv.value()+m_relDeltas[ColorSliders::Value]; double v = hsv.value() +m_relDeltas[ColorSliders::HsvValue] /100.0;
if (h < 0.0) h += 360.0; if (h < 0.0) h += 360.0;
else if (h > 360.0) h -= 360.0; else if (h > 360.0) h -= 360.0;
hsv.hue (MID(0.0, h, 360.0)); hsv.hue (MID(0.0, h, 360.0));
hsv.saturation(MID(0.0, s, 100.0) / 100.0); hsv.saturation(MID(0.0, s, 1.0));
hsv.value (MID(0.0, v, 100.0) / 100.0); hsv.value (MID(0.0, v, 1.0));
// Convert HSV back to RGB // Convert HSV back to RGB
Rgb rgb(hsv); Rgb rgb(hsv);
@ -643,6 +694,30 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
break; break;
} }
case app::Color::HslType: {
// Convert RGB to HSL
Hsl hsl(Rgb(r, g, b));
double h = hsl.hue() +m_relDeltas[ColorSliders::HslHue];
double s = hsl.saturation()+m_relDeltas[ColorSliders::HslSaturation]/100.0;
double l = hsl.lightness() +m_relDeltas[ColorSliders::HslLightness] /100.0;
if (h < 0.0) h += 360.0;
else if (h > 360.0) h -= 360.0;
hsl.hue (h);
hsl.saturation(MID(0.0, s, 1.0));
hsl.lightness (MID(0.0, l, 1.0));
// Convert HSL back to RGB
Rgb rgb(hsl);
r = rgb.red();
g = rgb.green();
b = rgb.blue();
a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255);
break;
}
} }
palette->setEntry(c, doc::rgba(r, g, b, a)); palette->setEntry(c, doc::rgba(r, g, b, a));
@ -654,12 +729,14 @@ void PaletteEntryEditor::selectColorType(app::Color::Type type)
m_type = type; m_type = type;
m_rgbSliders.setVisible(type == app::Color::RgbType); m_rgbSliders.setVisible(type == app::Color::RgbType);
m_hsvSliders.setVisible(type == app::Color::HsvType); m_hsvSliders.setVisible(type == app::Color::HsvType);
m_hslSliders.setVisible(type == app::Color::HslType);
resetRelativeInfo(); resetRelativeInfo();
switch (type) { switch (type) {
case app::Color::RgbType: m_colorType.setSelectedItem(RGB_MODE); break; case app::Color::RgbType: m_colorType.setSelectedItem(RGB_MODE); break;
case app::Color::HsvType: m_colorType.setSelectedItem(HSV_MODE); break; case app::Color::HsvType: m_colorType.setSelectedItem(HSV_MODE); break;
case app::Color::HslType: m_colorType.setSelectedItem(HSL_MODE); break;
} }
m_vbox.layout(); m_vbox.layout();
@ -747,6 +824,7 @@ void PaletteEntryEditor::resetRelativeInfo()
{ {
m_rgbSliders.resetRelativeSliders(); m_rgbSliders.resetRelativeSliders();
m_hsvSliders.resetRelativeSliders(); m_hsvSliders.resetRelativeSliders();
m_hslSliders.resetRelativeSliders();
get_current_palette()->copyColorsTo(&m_fromPalette); get_current_palette()->copyColorsTo(&m_fromPalette);
m_relDeltas.clear(); m_relDeltas.clear();
} }

View File

@ -52,6 +52,7 @@ private:
m_filter.setHue(double(m_sliders.getRelSliderValue(0))); m_filter.setHue(double(m_sliders.getRelSliderValue(0)));
m_filter.setSaturation(m_sliders.getRelSliderValue(1) / 100.0); m_filter.setSaturation(m_sliders.getRelSliderValue(1) / 100.0);
m_filter.setLightness(m_sliders.getRelSliderValue(2) / 100.0); m_filter.setLightness(m_sliders.getRelSliderValue(2) / 100.0);
m_filter.setAlpha(m_sliders.getRelSliderValue(3));
restartPreview(); restartPreview();
} }
@ -90,7 +91,8 @@ void HueSaturationCommand::onExecute(Context* context)
filterMgr.setTarget(TARGET_RED_CHANNEL | filterMgr.setTarget(TARGET_RED_CHANNEL |
TARGET_GREEN_CHANNEL | TARGET_GREEN_CHANNEL |
TARGET_BLUE_CHANNEL | TARGET_BLUE_CHANNEL |
TARGET_GRAY_CHANNEL); TARGET_GRAY_CHANNEL |
TARGET_ALPHA_CHANNEL);
HueSaturationWindow window(filter, filterMgr); HueSaturationWindow window(filter, filterMgr);
window.doModal(); window.doModal();

View File

@ -44,9 +44,11 @@ using namespace doc;
enum { enum {
INDEX_MODE, INDEX_MODE,
RGB_MODE, RGB_MODE,
HSB_MODE, HSV_MODE,
HSL_MODE,
GRAY_MODE, GRAY_MODE,
MASK_MODE MASK_MODE,
COLOR_MODES
}; };
static base::UniquePtr<doc::Palette> g_simplePal(nullptr); static base::UniquePtr<doc::Palette> g_simplePal(nullptr);
@ -124,7 +126,7 @@ ColorPopup::ColorPopup(const bool canPin,
, m_color(app::Color::fromMask()) , m_color(app::Color::fromMask())
, m_colorPalette(false, PaletteView::SelectOneColor, this, 7*guiscale()) , m_colorPalette(false, PaletteView::SelectOneColor, this, 7*guiscale())
, m_simpleColors(nullptr) , m_simpleColors(nullptr)
, m_colorType(5) , m_colorType(COLOR_MODES)
, m_maskLabel("Transparent Color Selected") , m_maskLabel("Transparent Color Selected")
, m_canPin(canPin) , m_canPin(canPin)
, m_disableHexUpdate(false) , m_disableHexUpdate(false)
@ -145,7 +147,8 @@ ColorPopup::ColorPopup(const bool canPin,
m_colorType.addItem("Index")->setFocusStop(false); m_colorType.addItem("Index")->setFocusStop(false);
m_colorType.addItem("RGB")->setFocusStop(false); m_colorType.addItem("RGB")->setFocusStop(false);
m_colorType.addItem("HSB")->setFocusStop(false); m_colorType.addItem("HSV")->setFocusStop(false);
m_colorType.addItem("HSL")->setFocusStop(false);
m_colorType.addItem("Gray")->setFocusStop(false); m_colorType.addItem("Gray")->setFocusStop(false);
m_colorType.addItem("Mask")->setFocusStop(false); m_colorType.addItem("Mask")->setFocusStop(false);
@ -156,6 +159,7 @@ ColorPopup::ColorPopup(const bool canPin,
m_colorPaletteContainer.setExpansive(true); m_colorPaletteContainer.setExpansive(true);
m_rgbSliders.setExpansive(true); m_rgbSliders.setExpansive(true);
m_hsvSliders.setExpansive(true); m_hsvSliders.setExpansive(true);
m_hslSliders.setExpansive(true);
m_graySlider.setExpansive(true); m_graySlider.setExpansive(true);
m_topBox.addChild(&m_colorType); m_topBox.addChild(&m_colorType);
@ -190,6 +194,7 @@ ColorPopup::ColorPopup(const bool canPin,
m_vbox.addChild(&m_colorPaletteContainer); m_vbox.addChild(&m_colorPaletteContainer);
m_vbox.addChild(&m_rgbSliders); m_vbox.addChild(&m_rgbSliders);
m_vbox.addChild(&m_hsvSliders); m_vbox.addChild(&m_hsvSliders);
m_vbox.addChild(&m_hslSliders);
m_vbox.addChild(&m_graySlider); m_vbox.addChild(&m_graySlider);
m_vbox.addChild(&m_maskLabel); m_vbox.addChild(&m_maskLabel);
addChild(&m_vbox); addChild(&m_vbox);
@ -198,6 +203,7 @@ ColorPopup::ColorPopup(const bool canPin,
m_rgbSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this); m_rgbSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
m_hsvSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this); m_hsvSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
m_hslSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
m_graySlider.ColorChange.connect(&ColorPopup::onColorSlidersChange, this); m_graySlider.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
m_hexColorEntry.ColorChange.connect(&ColorPopup::onColorHexEntryChange, this); m_hexColorEntry.ColorChange.connect(&ColorPopup::onColorHexEntryChange, this);
@ -240,6 +246,7 @@ void ColorPopup::setColor(const app::Color& color, SetColorOptions options)
m_rgbSliders.setColor(m_color); m_rgbSliders.setColor(m_color);
m_hsvSliders.setColor(m_color); m_hsvSliders.setColor(m_color);
m_hslSliders.setColor(m_color);
m_graySlider.setColor(m_color); m_graySlider.setColor(m_color);
if (!m_disableHexUpdate) if (!m_disableHexUpdate)
m_hexColorEntry.setColor(m_color); m_hexColorEntry.setColor(m_color);
@ -340,10 +347,16 @@ void ColorPopup::onColorTypeClick()
newColor.getBlue(), newColor.getBlue(),
newColor.getAlpha()); newColor.getAlpha());
break; break;
case HSB_MODE: case HSV_MODE:
newColor = app::Color::fromHsv(newColor.getHue(), newColor = app::Color::fromHsv(newColor.getHsvHue(),
newColor.getSaturation(), newColor.getHsvSaturation(),
newColor.getValue(), newColor.getHsvValue(),
newColor.getAlpha());
break;
case HSL_MODE:
newColor = app::Color::fromHsl(newColor.getHslHue(),
newColor.getHslSaturation(),
newColor.getHslLightness(),
newColor.getAlpha()); newColor.getAlpha());
break; break;
case GRAY_MODE: case GRAY_MODE:
@ -393,18 +406,20 @@ void ColorPopup::selectColorType(app::Color::Type type)
m_colorPaletteContainer.setVisible(type == app::Color::IndexType); m_colorPaletteContainer.setVisible(type == app::Color::IndexType);
m_rgbSliders.setVisible(type == app::Color::RgbType); m_rgbSliders.setVisible(type == app::Color::RgbType);
m_hsvSliders.setVisible(type == app::Color::HsvType); m_hsvSliders.setVisible(type == app::Color::HsvType);
m_hslSliders.setVisible(type == app::Color::HslType);
m_graySlider.setVisible(type == app::Color::GrayType); m_graySlider.setVisible(type == app::Color::GrayType);
m_maskLabel.setVisible(type == app::Color::MaskType); m_maskLabel.setVisible(type == app::Color::MaskType);
switch (type) { switch (type) {
case app::Color::IndexType: m_colorType.setSelectedItem(INDEX_MODE); break; case app::Color::IndexType: m_colorType.setSelectedItem(INDEX_MODE); break;
case app::Color::RgbType: m_colorType.setSelectedItem(RGB_MODE); break; case app::Color::RgbType: m_colorType.setSelectedItem(RGB_MODE); break;
case app::Color::HsvType: m_colorType.setSelectedItem(HSB_MODE); break; case app::Color::HsvType: m_colorType.setSelectedItem(HSV_MODE); break;
case app::Color::HslType: m_colorType.setSelectedItem(HSL_MODE); break;
case app::Color::GrayType: m_colorType.setSelectedItem(GRAY_MODE); break; case app::Color::GrayType: m_colorType.setSelectedItem(GRAY_MODE); break;
case app::Color::MaskType: m_colorType.setSelectedItem(MASK_MODE); break; case app::Color::MaskType: m_colorType.setSelectedItem(MASK_MODE); break;
} }
// Remove focus from hidden RGB/HSB text entries // Remove focus from hidden RGB/HSV/HSL text entries
auto widget = manager()->getFocus(); auto widget = manager()->getFocus();
if (widget && !widget->isVisible()) { if (widget && !widget->isVisible()) {
auto window = widget->window(); auto window = widget->window();

View File

@ -71,6 +71,7 @@ namespace app {
HexColorEntry m_hexColorEntry; HexColorEntry m_hexColorEntry;
RgbSliders m_rgbSliders; RgbSliders m_rgbSliders;
HsvSliders m_hsvSliders; HsvSliders m_hsvSliders;
HslSliders m_hslSliders;
GraySlider m_graySlider; GraySlider m_graySlider;
ui::Label m_maskLabel; ui::Label m_maskLabel;
obs::scoped_connection m_onPaletteChangeConn; obs::scoped_connection m_onPaletteChangeConn;

View File

@ -53,7 +53,7 @@ bool ColorSelector::onProcessMessage(ui::Message* msg)
scale = 15.0; scale = 15.0;
} }
double newHue = m_color.getHue() double newHue = m_color.getHsvHue()
+ scale*(+ static_cast<MouseMessage*>(msg)->wheelDelta().x + scale*(+ static_cast<MouseMessage*>(msg)->wheelDelta().x
- static_cast<MouseMessage*>(msg)->wheelDelta().y); - static_cast<MouseMessage*>(msg)->wheelDelta().y);
@ -61,12 +61,12 @@ bool ColorSelector::onProcessMessage(ui::Message* msg)
newHue += 360.0; newHue += 360.0;
newHue = std::fmod(newHue, 360.0); newHue = std::fmod(newHue, 360.0);
if (newHue != m_color.getHue()) { if (newHue != m_color.getHsvHue()) {
app::Color newColor = app::Color newColor =
app::Color::fromHsv( app::Color::fromHsv(
newHue, newHue,
m_color.getSaturation(), m_color.getHsvSaturation(),
m_color.getValue()); m_color.getHsvValue());
ColorChange(newColor, kButtonNone); ColorChange(newColor, kButtonNone);
} }

View File

@ -62,18 +62,49 @@ namespace {
case ColorSliders::Blue: case ColorSliders::Blue:
color = gfx::rgba(m_color.getRed(), m_color.getGreen(), 255 * x / w); color = gfx::rgba(m_color.getRed(), m_color.getGreen(), 255 * x / w);
break; break;
case ColorSliders::Hue:
color = color_utils::color_for_ui(app::Color::fromHsv(360 * x / w, m_color.getSaturation(), m_color.getValue())); case ColorSliders::HsvHue:
color = color_utils::color_for_ui(
app::Color::fromHsv(360.0 * x / w,
m_color.getHsvSaturation(),
m_color.getHsvValue()));
break; break;
case ColorSliders::Saturation: case ColorSliders::HsvSaturation:
color = color_utils::color_for_ui(app::Color::fromHsv(m_color.getHue(), 100 * x / w, m_color.getValue())); color = color_utils::color_for_ui(
app::Color::fromHsv(m_color.getHsvHue(),
double(x) / double(w),
m_color.getHsvValue()));
break; break;
case ColorSliders::Value: case ColorSliders::HsvValue:
color = color_utils::color_for_ui(app::Color::fromHsv(m_color.getHue(), m_color.getSaturation(), 100 * x / w)); color = color_utils::color_for_ui(
app::Color::fromHsv(m_color.getHsvHue(),
m_color.getHsvSaturation(),
double(x) / double(w)));
break; break;
case ColorSliders::HslHue:
color = color_utils::color_for_ui(
app::Color::fromHsl(360.0 * x / w,
m_color.getHslSaturation(),
m_color.getHslLightness()));
break;
case ColorSliders::HslSaturation:
color = color_utils::color_for_ui(
app::Color::fromHsl(m_color.getHslHue(),
double(x) / double(w),
m_color.getHslLightness()));
break;
case ColorSliders::HslLightness:
color = color_utils::color_for_ui(
app::Color::fromHsl(m_color.getHslHue(),
m_color.getHslSaturation(),
double(x) / double(w)));
break;
case ColorSliders::Gray: case ColorSliders::Gray:
case ColorSliders::Alpha: case ColorSliders::Alpha:
color = color_utils::color_for_ui(app::Color::fromGray(255 * x / w)); color = color_utils::color_for_ui(
app::Color::fromGray(255 * x / w));
break; break;
} }
g->drawVLine(color, rc.x+x, rc.y, rc.h); g->drawVLine(color, rc.x+x, rc.y, rc.h);
@ -390,25 +421,25 @@ app::Color RgbSliders::getColorFromSliders()
HsvSliders::HsvSliders() HsvSliders::HsvSliders()
: ColorSliders() : ColorSliders()
{ {
addSlider(Hue, "H", 0, 360, -180, 180); addSlider(HsvHue, "H", 0, 360, -180, 180);
addSlider(Saturation, "S", 0, 100, -100, 100); addSlider(HsvSaturation, "S", 0, 100, -100, 100);
addSlider(Value, "B", 0, 100, -100, 100); addSlider(HsvValue, "V", 0, 100, -100, 100);
addSlider(Alpha, "A", 0, 255, -255, 255); addSlider(Alpha, "A", 0, 255, -255, 255);
} }
void HsvSliders::onSetColor(const app::Color& color) void HsvSliders::onSetColor(const app::Color& color)
{ {
setAbsSliderValue(0, int(color.getHue())); setAbsSliderValue(0, int(color.getHsvHue()));
setAbsSliderValue(1, int(color.getSaturation())); setAbsSliderValue(1, int(color.getHsvSaturation() * 100.0));
setAbsSliderValue(2, int(color.getValue())); setAbsSliderValue(2, int(color.getHsvValue() * 100.0));
setAbsSliderValue(3, color.getAlpha()); setAbsSliderValue(3, color.getAlpha());
} }
app::Color HsvSliders::getColorFromSliders() app::Color HsvSliders::getColorFromSliders()
{ {
return app::Color::fromHsv(getAbsSliderValue(0), return app::Color::fromHsv(getAbsSliderValue(0),
getAbsSliderValue(1), getAbsSliderValue(1) / 100.0,
getAbsSliderValue(2), getAbsSliderValue(2) / 100.0,
getAbsSliderValue(3)); getAbsSliderValue(3));
} }
@ -418,31 +449,26 @@ app::Color HsvSliders::getColorFromSliders()
HslSliders::HslSliders() HslSliders::HslSliders()
: ColorSliders() : ColorSliders()
{ {
addSlider(Hue, "H", 0, 360, -180, 180); addSlider(HslHue, "H", 0, 360, -180, 180);
addSlider(Saturation, "S", 0, 100, -100, 100); addSlider(HslSaturation, "S", 0, 100, -100, 100);
addSlider(Value, "L", 0, 100, -100, 100); addSlider(HslLightness, "L", 0, 100, -100, 100);
addSlider(Alpha, "A", 0, 255, -255, 255);
} }
void HslSliders::onSetColor(const app::Color& color) void HslSliders::onSetColor(const app::Color& color)
{ {
gfx::Hsl hsl(gfx::Rgb(color.getRed(), setAbsSliderValue(0, int(color.getHslHue()));
color.getGreen(), setAbsSliderValue(1, int(color.getHslSaturation() * 100.0));
color.getBlue())); setAbsSliderValue(2, int(color.getHslLightness() * 100.0));
setAbsSliderValue(3, color.getAlpha());
setAbsSliderValue(0, hsl.hue());
setAbsSliderValue(1, hsl.saturation() * 100.0);
setAbsSliderValue(2, hsl.lightness() * 100.0);
} }
app::Color HslSliders::getColorFromSliders() app::Color HslSliders::getColorFromSliders()
{ {
gfx::Hsl hsl(getAbsSliderValue(0), return app::Color::fromHsl(getAbsSliderValue(0),
getAbsSliderValue(1) / 100.0, getAbsSliderValue(1) / 100.0,
getAbsSliderValue(2) / 100.0); getAbsSliderValue(2) / 100.0,
gfx::Rgb rgb(hsl); getAbsSliderValue(3));
return app::Color::fromRgb(rgb.red(),
rgb.green(),
rgb.blue(), 255);
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@ -29,9 +29,9 @@ namespace app {
class ColorSliders : public ui::Widget { class ColorSliders : public ui::Widget {
public: public:
enum Channel { Red, Green, Blue, enum Channel { Red, Green, Blue,
Hue, Saturation, Value, HsvHue, HsvSaturation, HsvValue,
Gray, HslHue, HslSaturation, HslLightness,
Alpha }; Gray, Alpha };
enum Mode { Absolute, Relative }; enum Mode { Absolute, Relative };
ColorSliders(); ColorSliders();

View File

@ -55,13 +55,13 @@ app::Color ColorSpectrum::getColorByPosition(const gfx::Point& pos)
} }
double hue = 360.0 * u / umax; double hue = 360.0 * u / umax;
double sat = (v < vmid ? 100.0 * v / vmid : 100.0); double sat = (v < vmid ? double(v) / double(vmid) : 1.0);
double val = (v < vmid ? 100.0 : 100.0-(100.0 * (v-vmid) / vmid)); double val = (v < vmid ? 1.0 : 1.0-(double(v-vmid) / double(vmid)));
return app::Color::fromHsv( return app::Color::fromHsv(
MID(0.0, hue, 360.0), MID(0.0, hue, 360.0),
MID(0.0, sat, 100.0), MID(0.0, sat, 1.0),
MID(0.0, val, 100.0)); MID(0.0, val, 1.0));
} }
void ColorSpectrum::onPaint(ui::PaintEvent& ev) void ColorSpectrum::onPaint(ui::PaintEvent& ev)
@ -95,31 +95,31 @@ void ColorSpectrum::onPaint(ui::PaintEvent& ev)
} }
double hue = 360.0 * u / umax; double hue = 360.0 * u / umax;
double sat = (v < vmid ? 100.0 * v / vmid : 100.0); double sat = (v < vmid ? double(v) / double(vmid) : 1.0);
double val = (v < vmid ? 100.0 : 100.0-(100.0 * (v-vmid) / vmid)); double val = (v < vmid ? 1.0 : 1.0-(double(v-vmid) / double(vmid)));
gfx::Color color = color_utils::color_for_ui( gfx::Color color = color_utils::color_for_ui(
app::Color::fromHsv( app::Color::fromHsv(
MID(0.0, hue, 360.0), MID(0.0, hue, 360.0),
MID(0.0, sat, 100.0), MID(0.0, sat, 1.0),
MID(0.0, val, 100.0))); MID(0.0, val, 1.0)));
g->putPixel(color, rc.x+x, rc.y+y); g->putPixel(color, rc.x+x, rc.y+y);
} }
} }
if (m_color.getType() != app::Color::MaskType) { if (m_color.getType() != app::Color::MaskType) {
double hue = m_color.getHue(); double hue = m_color.getHsvHue();
double sat = m_color.getSaturation(); double sat = m_color.getHsvSaturation();
double val = m_color.getValue(); double val = m_color.getHsvValue();
double lit = (200.0 - sat) * val / 200.0; double lit = (2.0 - sat) * val / 2.0;
gfx::Point pos(rc.x + int(hue * rc.w / 360.0), gfx::Point pos(rc.x + int(hue * rc.w / 360.0),
rc.y + rc.h - int(lit * rc.h / 100.0)); rc.y + rc.h - int(lit * rc.h));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0); she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawColoredRgbaSurface( g->drawColoredRgbaSurface(
icon, icon,
lit > 50.0 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255), lit > 0.5 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
pos.x-icon->width()/2, pos.x-icon->width()/2,
pos.y-icon->height()/2); pos.y-icon->height()/2);
} }

View File

@ -54,19 +54,19 @@ app::Color ColorTintShadeTone::getColorByPosition(const gfx::Point& pos)
if (inHue) { if (inHue) {
hue = (360.0 * u / umax); hue = (360.0 * u / umax);
sat = m_color.getSaturation(); sat = m_color.getHsvSaturation();
val = m_color.getValue(); val = m_color.getHsvValue();
} }
else { else {
hue = m_color.getHue(); hue = m_color.getHsvHue();
sat = (100.0 * u / umax); sat = (1.0 * u / umax);
val = (100.0 - 100.0 * v / vmax); val = (1.0 - double(v) / double(vmax));
} }
return app::Color::fromHsv( return app::Color::fromHsv(
MID(0.0, hue, 360.0), MID(0.0, hue, 360.0),
MID(0.0, sat, 100.0), MID(0.0, sat, 1.0),
MID(0.0, val, 100.0)); MID(0.0, val, 1.0));
} }
void ColorTintShadeTone::onPaint(ui::PaintEvent& ev) void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
@ -82,7 +82,7 @@ void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
if (rc.isEmpty()) if (rc.isEmpty())
return; return;
double hue = m_color.getHue(); double hue = m_color.getHsvHue();
int umax, vmax; int umax, vmax;
int huebar = getHueBarSize(); int huebar = getHueBarSize();
umax = MAX(1, rc.w-1); umax = MAX(1, rc.w-1);
@ -90,14 +90,14 @@ void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
for (int y=0; y<rc.h-huebar; ++y) { for (int y=0; y<rc.h-huebar; ++y) {
for (int x=0; x<rc.w; ++x) { for (int x=0; x<rc.w; ++x) {
double sat = (100.0 * x / umax); double sat = double(x) / double(umax);
double val = (100.0 - 100.0 * y / vmax); double val = 1.0 - double(y) / double(vmax);
gfx::Color color = color_utils::color_for_ui( gfx::Color color = color_utils::color_for_ui(
app::Color::fromHsv( app::Color::fromHsv(
hue, hue,
MID(0.0, sat, 100.0), MID(0.0, sat, 1.0),
MID(0.0, val, 100.0))); MID(0.0, val, 1.0)));
g->putPixel(color, rc.x+x, rc.y+y); g->putPixel(color, rc.x+x, rc.y+y);
} }
@ -108,7 +108,7 @@ void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
for (int x=0; x<rc.w; ++x) { for (int x=0; x<rc.w; ++x) {
gfx::Color color = color_utils::color_for_ui( gfx::Color color = color_utils::color_for_ui(
app::Color::fromHsv( app::Color::fromHsv(
(360.0 * x / rc.w), 100.0, 100.0)); (360.0 * x / rc.w), 1.0, 1.0));
g->putPixel(color, rc.x+x, rc.y+y); g->putPixel(color, rc.x+x, rc.y+y);
} }
@ -116,15 +116,15 @@ void ColorTintShadeTone::onPaint(ui::PaintEvent& ev)
} }
if (m_color.getType() != app::Color::MaskType) { if (m_color.getType() != app::Color::MaskType) {
double sat = m_color.getSaturation(); double sat = m_color.getHsvSaturation();
double val = m_color.getValue(); double val = m_color.getHsvValue();
gfx::Point pos(rc.x + int(sat * rc.w / 100.0), gfx::Point pos(rc.x + int(sat * rc.w),
rc.y + int((100.0-val) * (rc.h-huebar) / 100.0)); rc.y + int((1.0-val) * (rc.h-huebar)));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0); she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawColoredRgbaSurface( g->drawColoredRgbaSurface(
icon, icon,
val > 50.0 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255), val > 0.5 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
pos.x-icon->width()/2, pos.x-icon->width()/2,
pos.y-icon->height()/2); pos.y-icon->height()/2);

View File

@ -105,8 +105,8 @@ app::Color ColorWheel::getColorInClientPos(const gfx::Point& pos)
return app::Color::fromHsv( return app::Color::fromHsv(
MID(0, hue, 360), MID(0, hue, 360),
MID(0, sat, 100), MID(0, sat / 100.0, 1.0),
100); 1.0);
} }
// Pick harmonies // Pick harmonies
@ -123,9 +123,9 @@ app::Color ColorWheel::getColorInClientPos(const gfx::Point& pos)
boxsize, boxsize).contains(pos)) { boxsize, boxsize).contains(pos)) {
m_harmonyPicked = true; m_harmonyPicked = true;
color = app::Color::fromHsv(convertHueAngle(int(color.getHue()), 1), color = app::Color::fromHsv(convertHueAngle(int(color.getHsvHue()), 1),
color.getSaturation(), color.getHsvSaturation(),
color.getValue()); color.getHsvValue());
return color; return color;
} }
} }
@ -168,11 +168,11 @@ app::Color ColorWheel::getColorInHarmony(int j) const
{ {
int i = MID(0, (int)m_harmony, (int)Harmony::LAST); int i = MID(0, (int)m_harmony, (int)Harmony::LAST);
j = MID(0, j, harmonies[i].n-1); j = MID(0, j, harmonies[i].n-1);
double hue = convertHueAngle(int(m_color.getHue()), -1) + harmonies[i].hues[j]; double hue = convertHueAngle(int(m_color.getHsvHue()), -1) + harmonies[i].hues[j];
double sat = m_color.getSaturation() * harmonies[i].sats[j] / 100.0; double sat = m_color.getHsvSaturation() * harmonies[i].sats[j] / 100.0;
return app::Color::fromHsv(std::fmod(hue, 360), return app::Color::fromHsv(std::fmod(hue, 360),
MID(0.0, sat, 100.0), MID(0.0, sat, 1.0),
m_color.getValue()); m_color.getHsvValue());
} }
void ColorWheel::onResize(ui::ResizeEvent& ev) void ColorWheel::onResize(ui::ResizeEvent& ev)
@ -230,17 +230,17 @@ void ColorWheel::onPaint(ui::PaintEvent& ev)
for (int i=0; i<n; ++i) { for (int i=0; i<n; ++i) {
app::Color color = getColorInHarmony(i); app::Color color = getColorInHarmony(i);
double angle = color.getHue()-30.0; double angle = color.getHsvHue()-30.0;
double dist = color.getSaturation(); double dist = color.getHsvSaturation();
color = app::Color::fromHsv(convertHueAngle(int(color.getHue()), 1), color = app::Color::fromHsv(convertHueAngle(int(color.getHsvHue()), 1),
color.getSaturation(), color.getHsvSaturation(),
color.getValue()); color.getHsvValue());
gfx::Point pos = gfx::Point pos =
m_wheelBounds.center() + m_wheelBounds.center() +
gfx::Point(int(+std::cos(PI*angle/180.0)*double(m_wheelRadius)*dist/100.0), gfx::Point(int(+std::cos(PI*angle/180.0)*double(m_wheelRadius)*dist),
int(-std::sin(PI*angle/180.0)*double(m_wheelRadius)*dist/100.0)); int(-std::sin(PI*angle/180.0)*double(m_wheelRadius)*dist));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0); she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawRgbaSurface(icon, g->drawRgbaSurface(icon,

View File

@ -1249,8 +1249,10 @@ public:
m_channel.addItem("Alpha"); m_channel.addItem("Alpha");
m_channel.addItem("RGB+Alpha"); m_channel.addItem("RGB+Alpha");
m_channel.addItem("RGB"); m_channel.addItem("RGB");
m_channel.addItem("HSB+Alpha"); m_channel.addItem("HSV+Alpha");
m_channel.addItem("HSB"); m_channel.addItem("HSV");
m_channel.addItem("HSL+Alpha");
m_channel.addItem("HSL");
m_channel.addItem("Gray+Alpha"); m_channel.addItem("Gray+Alpha");
m_channel.addItem("Gray"); m_channel.addItem("Gray");
m_channel.addItem("Best fit Index"); m_channel.addItem("Best fit Index");

View File

@ -951,6 +951,7 @@ int PaletteView::findExactIndex(const app::Color& color) const
case Color::RgbType: case Color::RgbType:
case Color::HsvType: case Color::HsvType:
case Color::HslType:
case Color::GrayType: case Color::GrayType:
return currentPalette()->findExactMatch( return currentPalette()->findExactMatch(
color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha(), -1); color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha(), -1);

View File

@ -33,6 +33,7 @@ HueSaturationFilter::HueSaturationFilter()
: m_h(0.0) : m_h(0.0)
, m_s(0.0) , m_s(0.0)
, m_l(0.0) , m_l(0.0)
, m_a(0)
{ {
} }
@ -51,6 +52,11 @@ void HueSaturationFilter::setLightness(double l)
m_l = l; m_l = l;
} }
void HueSaturationFilter::setAlpha(int a)
{
m_a = a;
}
void HueSaturationFilter::applyToRgba(FilterManager* filterMgr) void HueSaturationFilter::applyToRgba(FilterManager* filterMgr)
{ {
const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress(); const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress();
@ -95,6 +101,9 @@ void HueSaturationFilter::applyToRgba(FilterManager* filterMgr)
if (target & TARGET_RED_CHANNEL ) r = rgb.red(); if (target & TARGET_RED_CHANNEL ) r = rgb.red();
if (target & TARGET_GREEN_CHANNEL) g = rgb.green(); if (target & TARGET_GREEN_CHANNEL) g = rgb.green();
if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue(); if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue();
if (a && (target & TARGET_ALPHA_CHANNEL))
a = MID(0, a+m_a, 255);
} }
*(dst_address++) = rgba(r, g, b, a); *(dst_address++) = rgba(r, g, b, a);
@ -131,6 +140,9 @@ void HueSaturationFilter::applyToGrayscale(FilterManager* filterMgr)
gfx::Rgb rgb(hsl); gfx::Rgb rgb(hsl);
if (target & TARGET_GRAY_CHANNEL) k = rgb.red(); if (target & TARGET_GRAY_CHANNEL) k = rgb.red();
if (a && (target & TARGET_ALPHA_CHANNEL))
a = MID(0, a+m_a, 255);
} }
*(dst_address++) = graya(k, a); *(dst_address++) = graya(k, a);
@ -182,6 +194,9 @@ void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr)
if (target & TARGET_RED_CHANNEL ) r = rgb.red(); if (target & TARGET_RED_CHANNEL ) r = rgb.red();
if (target & TARGET_GREEN_CHANNEL) g = rgb.green(); if (target & TARGET_GREEN_CHANNEL) g = rgb.green();
if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue(); if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue();
if (a && (target & TARGET_ALPHA_CHANNEL))
a = MID(0, a+m_a, 255);
} }
c = rgbmap->mapColor(r, g, b, a); c = rgbmap->mapColor(r, g, b, a);

View File

@ -19,6 +19,7 @@ namespace filters {
void setHue(double h); void setHue(double h);
void setSaturation(double s); void setSaturation(double s);
void setLightness(double v); void setLightness(double v);
void setAlpha(int a);
// Filter implementation // Filter implementation
const char* getName(); const char* getName();
@ -28,6 +29,7 @@ namespace filters {
private: private:
double m_h, m_s, m_l; double m_h, m_s, m_l;
int m_a;
}; };
} // namespace filters } // namespace filters

View File

@ -18,16 +18,12 @@ using namespace std;
Hsl::Hsl(double hue, double saturation, double lightness) Hsl::Hsl(double hue, double saturation, double lightness)
: m_hue(hue) : m_hue(hue)
, m_saturation(saturation) , m_saturation(MID(0.0, saturation, 1.0))
, m_lightness(lightness) , m_lightness(MID(0.0, lightness, 1.0))
{ {
while (m_hue < 0.0) while (m_hue < 0.0)
m_hue += 360.0; m_hue += 360.0;
m_hue = std::fmod(m_hue, 360.0); m_hue = std::fmod(m_hue, 360.0);
assert(hue >= 0.0 && hue <= 360.0);
assert(saturation >= 0.0 && saturation <= 1.0);
assert(lightness >= 0.0 && lightness <= 1.0);
} }
Hsl::Hsl(const Rgb& rgb) Hsl::Hsl(const Rgb& rgb)
@ -76,17 +72,17 @@ Hsl::Hsl(const Rgb& rgb)
int Hsl::hueInt() const int Hsl::hueInt() const
{ {
return int(floor(m_hue + 0.5)); return int(std::floor(m_hue + 0.5));
} }
int Hsl::saturationInt() const int Hsl::saturationInt() const
{ {
return int(floor(m_saturation*100.0 + 0.5)); return int(std::floor(m_saturation*100.0 + 0.5));
} }
int Hsl::lightnessInt() const int Hsl::lightnessInt() const
{ {
return int(floor(m_lightness*100.0 + 0.5)); return int(std::floor(m_lightness*100.0 + 0.5));
} }
} // namespace gfx } // namespace gfx

View File

@ -8,7 +8,7 @@
#define GFX_HSL_H_INCLUDED #define GFX_HSL_H_INCLUDED
#pragma once #pragma once
#include <cassert> #include "base/base.h" // MID
namespace gfx { namespace gfx {
@ -48,18 +48,15 @@ public:
int lightnessInt() const; int lightnessInt() const;
void hue(double hue) { void hue(double hue) {
assert(hue >= 0.0 && hue <= 360.0); m_hue = MID(0.0, hue, 360.0);
m_hue = hue;
} }
void saturation(double saturation) { void saturation(double saturation) {
assert(saturation >= 0.0 && saturation <= 1.0); m_saturation = MID(0.0, saturation, 1.0);
m_saturation = saturation;
} }
void lightness(double lightness) { void lightness(double lightness) {
assert(lightness >= 0.0 && lightness <= 1.0); m_lightness = MID(0.0, lightness, 1.0);
m_lightness = lightness;
} }
// The comparison is done through the integer value of each component. // The comparison is done through the integer value of each component.

View File

@ -18,16 +18,12 @@ using namespace std;
Hsv::Hsv(double hue, double saturation, double value) Hsv::Hsv(double hue, double saturation, double value)
: m_hue(hue) : m_hue(hue)
, m_saturation(saturation) , m_saturation(MID(0.0, saturation, 1.0))
, m_value(value) , m_value(MID(0.0, value, 1.0))
{ {
while (m_hue < 0.0) while (m_hue < 0.0)
m_hue += 360.0; m_hue += 360.0;
m_hue = std::fmod(m_hue, 360.0); m_hue = std::fmod(m_hue, 360.0);
assert(hue >= 0.0 && hue <= 360.0);
assert(saturation >= 0.0 && saturation <= 1.0);
assert(value >= 0.0 && value <= 1.0);
} }
// Reference: http://en.wikipedia.org/wiki/HSL_and_HSV // Reference: http://en.wikipedia.org/wiki/HSL_and_HSV
@ -77,17 +73,17 @@ Hsv::Hsv(const Rgb& rgb)
int Hsv::hueInt() const int Hsv::hueInt() const
{ {
return int(floor(m_hue + 0.5)); return int(std::floor(m_hue + 0.5));
} }
int Hsv::saturationInt() const int Hsv::saturationInt() const
{ {
return int(floor(m_saturation*100.0 + 0.5)); return int(std::floor(m_saturation*100.0 + 0.5));
} }
int Hsv::valueInt() const int Hsv::valueInt() const
{ {
return int(floor(m_value*100.0 + 0.5)); return int(std::floor(m_value*100.0 + 0.5));
} }
} // namespace gfx } // namespace gfx

View File

@ -8,7 +8,7 @@
#define GFX_HSV_H_INCLUDED #define GFX_HSV_H_INCLUDED
#pragma once #pragma once
#include <cassert> #include "base/base.h" // MID
namespace gfx { namespace gfx {
@ -48,18 +48,15 @@ public:
int valueInt() const; int valueInt() const;
void hue(double hue) { void hue(double hue) {
assert(hue >= 0.0 && hue <= 360.0); m_hue = MID(0.0, hue, 360.0);
m_hue = hue;
} }
void saturation(double saturation) { void saturation(double saturation) {
assert(saturation >= 0.0 && saturation <= 1.0); m_saturation = MID(0.0, saturation, 1.0);
m_saturation = saturation;
} }
void value(double value) { void value(double value) {
assert(value >= 0.0 && value <= 1.0); m_value = MID(0.0, value, 1.0);
m_value = value;
} }
// The comparison is done through the integer value of each component. // The comparison is done through the integer value of each component.