[aseprite] 226/308: Add more precision to HSV <-> RGB conversion (fix #961)
Tobias Hansen
thansen at moszumanska.debian.org
Tue Mar 8 02:45:14 UTC 2016
This is an automated email from the git hooks/post-receive script.
thansen pushed a commit to branch master
in repository aseprite.
commit 3f47c23cd8d4566036be1053dd9707ae83a63bb0
Author: David Capello <davidcapello at gmail.com>
Date: Fri Feb 12 13:01:32 2016 -0300
Add more precision to HSV <-> RGB conversion (fix #961)
This patch fixes problems using the eyedropper tool in HSB mode. If we
use "int" precision for HSB values, the resulting RGB color could be
different from the original one.
---
src/app/color.cpp | 101 ++++++++++++++++++++++--------------------
src/app/color.h | 13 +++---
src/app/ui/color_sliders.cpp | 6 +--
src/app/ui/color_spectrum.cpp | 40 ++++++++---------
src/app/ui/color_wheel.cpp | 20 ++++-----
5 files changed, 92 insertions(+), 88 deletions(-)
diff --git a/src/app/color.cpp b/src/app/color.cpp
index dbacd7f..577d5a2 100644
--- a/src/app/color.cpp
+++ b/src/app/color.cpp
@@ -1,5 +1,5 @@
// Aseprite
-// Copyright (C) 2001-2015 David Capello
+// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@@ -46,7 +46,7 @@ Color Color::fromRgb(int r, int g, int b, int a)
}
// static
-Color Color::fromHsv(int h, int s, int v, int a)
+Color Color::fromHsv(double h, double s, double v, int a)
{
Color color(Color::HsvType);
color.m_value.hsv.h = h;
@@ -124,24 +124,25 @@ Color Color::fromString(const std::string& str)
if (str.find("rgb{") == 0 ||
str.find("hsv{") == 0 ||
str.find("gray{") == 0) {
- int c = 0, table[4] = { 0, 0, 0, 255 };
+ int c = 0;
+ double table[4] = { 0.0, 0.0, 0.0, 255.0 };
std::string::size_type i = str.find_first_of('{')+1, j;
while ((j = str.find_first_of(",}", i)) != std::string::npos) {
std::string element = str.substr(i, j - i);
if (c < 4)
- table[c++] = std::strtol(element.c_str(), NULL, 10);
+ table[c++] = std::strtod(element.c_str(), NULL);
if (c >= 4)
break;
i = j+1;
}
if (str[0] == 'r')
- color = Color::fromRgb(table[0], table[1], table[2], table[3]);
+ color = Color::fromRgb(table[0], table[1], table[2], int(table[3]));
else if (str[0] == 'h')
- color = Color::fromHsv(table[0], table[1], table[2], table[3]);
+ color = Color::fromHsv(table[0], table[1], table[2], int(table[3]));
else if (str[0] == 'g')
- color = Color::fromGray(table[0], c >= 2 ? table[1]: 255);
+ color = Color::fromGray(table[0], (c >= 2 ? int(table[1]): 255));
}
else if (str.find("index{") == 0) {
color = Color::fromIndex(std::strtol(str.c_str()+6, NULL, 10));
@@ -171,6 +172,8 @@ std::string Color::toString() const
case Color::HsvType:
result << "hsv{"
+ << std::setprecision(2)
+ << std::fixed
<< m_value.hsv.h << ","
<< m_value.hsv.s << ","
<< m_value.hsv.v << ","
@@ -225,9 +228,9 @@ std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableS
}
else {
result << "HSB "
- << m_value.hsv.h << "\xc2\xb0 "
- << m_value.hsv.s << " "
- << m_value.hsv.v;
+ << int(m_value.hsv.h) << "\xc2\xb0 "
+ << int(m_value.hsv.s) << "% "
+ << int(m_value.hsv.v) << "%";
if (pixelFormat == IMAGE_INDEXED)
result << " Index " << color_utils::color_for_image(*this, pixelFormat);
@@ -290,9 +293,9 @@ std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableS
result << "Gry-" << getGray();
}
else {
- result << m_value.hsv.h << "\xc2\xb0"
- << m_value.hsv.s << ","
- << m_value.hsv.v;
+ result << int(m_value.hsv.h) << "\xc2\xb0"
+ << int(m_value.hsv.s) << ","
+ << int(m_value.hsv.v);
}
break;
@@ -332,10 +335,10 @@ bool Color::operator==(const Color& other) const
case Color::HsvType:
return
- m_value.hsv.h == other.m_value.hsv.h &&
- m_value.hsv.s == other.m_value.hsv.s &&
- m_value.hsv.v == other.m_value.hsv.v &&
- m_value.hsv.a == other.m_value.hsv.a;
+ (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.v - other.m_value.hsv.v) < 0.001) &&
+ (m_value.hsv.a == other.m_value.hsv.a);
case Color::GrayType:
return
@@ -379,8 +382,8 @@ int Color::getRed() const
case Color::HsvType:
return Rgb(Hsv(m_value.hsv.h,
- double(m_value.hsv.s) / 100.0,
- double(m_value.hsv.v) / 100.0)).red();
+ m_value.hsv.s / 100.0,
+ m_value.hsv.v / 100.0)).red();
case Color::GrayType:
return m_value.gray.g;
@@ -411,8 +414,8 @@ int Color::getGreen() const
case Color::HsvType:
return Rgb(Hsv(m_value.hsv.h,
- double(m_value.hsv.s) / 100.0,
- double(m_value.hsv.v) / 100.0)).green();
+ m_value.hsv.s / 100.0,
+ m_value.hsv.v / 100.0)).green();
case Color::GrayType:
return m_value.gray.g;
@@ -443,8 +446,8 @@ int Color::getBlue() const
case Color::HsvType:
return Rgb(Hsv(m_value.hsv.h,
- double(m_value.hsv.s) / 100.0,
- double(m_value.hsv.v) / 100.0)).blue();
+ m_value.hsv.s / 100.0,
+ m_value.hsv.v / 100.0)).blue();
case Color::GrayType:
return m_value.gray.g;
@@ -463,23 +466,23 @@ int Color::getBlue() const
return -1;
}
-int Color::getHue() const
+double Color::getHue() const
{
switch (getType()) {
case Color::MaskType:
- return 0;
+ return 0.0;
case Color::RgbType:
return Hsv(Rgb(m_value.rgb.r,
m_value.rgb.g,
- m_value.rgb.b)).hueInt();
+ m_value.rgb.b)).hue();
case Color::HsvType:
return m_value.hsv.h;
case Color::GrayType:
- return 0;
+ return 0.0;
case Color::IndexType: {
int i = m_value.index;
@@ -487,19 +490,19 @@ int Color::getHue() const
uint32_t c = get_current_palette()->getEntry(i);
return Hsv(Rgb(rgba_getr(c),
rgba_getg(c),
- rgba_getb(c))).hueInt();
+ rgba_getb(c))).hue();
}
else
- return 0;
+ return 0.0;
}
}
ASSERT(false);
- return -1;
+ return -1.0;
}
-int Color::getSaturation() const
+double Color::getSaturation() const
{
switch (getType()) {
@@ -509,7 +512,7 @@ int Color::getSaturation() const
case Color::RgbType:
return Hsv(Rgb(m_value.rgb.r,
m_value.rgb.g,
- m_value.rgb.b)).saturationInt();
+ m_value.rgb.b)).saturation() * 100.0;
case Color::HsvType:
return m_value.hsv.s;
@@ -523,35 +526,35 @@ int Color::getSaturation() const
uint32_t c = get_current_palette()->getEntry(i);
return Hsv(Rgb(rgba_getr(c),
rgba_getg(c),
- rgba_getb(c))).saturationInt();
+ rgba_getb(c))).saturation() * 100.0;
}
else
- return 0;
+ return 0.0;
}
}
ASSERT(false);
- return -1;
+ return -1.0;
}
-int Color::getValue() const
+double Color::getValue() const
{
switch (getType()) {
case Color::MaskType:
- return 0;
+ return 0.0;
case Color::RgbType:
return Hsv(Rgb(m_value.rgb.r,
m_value.rgb.g,
- m_value.rgb.b)).valueInt();
+ m_value.rgb.b)).value() * 100.0;
case Color::HsvType:
return m_value.hsv.v;
case Color::GrayType:
- return 100 * m_value.gray.g / 255;
+ return 100.0 * m_value.gray.g / 255.0;
case Color::IndexType: {
int i = m_value.index;
@@ -559,16 +562,16 @@ int Color::getValue() const
uint32_t c = get_current_palette()->getEntry(i);
return Hsv(Rgb(rgba_getr(c),
rgba_getg(c),
- rgba_getb(c))).valueInt();
+ rgba_getb(c))).value() * 100.0;
}
else
- return 0;
+ return 0.0;
}
}
ASSERT(false);
- return -1;
+ return -1.0;
}
int Color::getGray() const
@@ -579,12 +582,12 @@ int Color::getGray() const
return 0;
case Color::RgbType:
- return 255 * Hsv(Rgb(m_value.rgb.r,
- m_value.rgb.g,
- m_value.rgb.b)).valueInt() / 100;
+ return int(255.0 * Hsv(Rgb(m_value.rgb.r,
+ m_value.rgb.g,
+ m_value.rgb.b)).value() / 100.0);
case Color::HsvType:
- return 255 * m_value.hsv.v / 100;
+ return int(255.0 * m_value.hsv.v / 100.0);
case Color::GrayType:
return m_value.gray.g;
@@ -593,9 +596,9 @@ int Color::getGray() const
int i = m_value.index;
if (i >= 0 && i < get_current_palette()->size()) {
uint32_t c = get_current_palette()->getEntry(i);
- return 255 * Hsv(Rgb(rgba_getr(c),
- rgba_getg(c),
- rgba_getb(c))).valueInt() / 100;
+ return int(255.0 * Hsv(Rgb(rgba_getr(c),
+ rgba_getg(c),
+ rgba_getb(c))).value() / 100.0);
}
else
return 0;
diff --git a/src/app/color.h b/src/app/color.h
index 711ec72..a8c8ea5 100644
--- a/src/app/color.h
+++ b/src/app/color.h
@@ -1,5 +1,5 @@
// Aseprite
-// Copyright (C) 2001-2015 David Capello
+// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@@ -43,7 +43,7 @@ namespace app {
static Color fromMask();
static Color fromRgb(int r, int g, int b, int a = 255);
- static Color fromHsv(int h, int s, int 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,100], v=[0,100]
static Color fromGray(int g, int a = 255);
static Color fromIndex(int index);
@@ -69,9 +69,9 @@ namespace app {
int getRed() const;
int getGreen() const;
int getBlue() const;
- int getHue() const;
- int getSaturation() const;
- int getValue() const;
+ double getHue() const;
+ double getSaturation() const;
+ double getValue() const;
int getGray() const;
int getIndex() const;
int getAlpha() const;
@@ -88,7 +88,8 @@ namespace app {
int r, g, b, a;
} rgb;
struct {
- int h, s, v, a;
+ double h, s, v;
+ int a;
} hsv;
struct {
int g, a;
diff --git a/src/app/ui/color_sliders.cpp b/src/app/ui/color_sliders.cpp
index 1ccde37..c9c9f6a 100644
--- a/src/app/ui/color_sliders.cpp
+++ b/src/app/ui/color_sliders.cpp
@@ -283,9 +283,9 @@ HsvSliders::HsvSliders()
void HsvSliders::onSetColor(const app::Color& color)
{
- setAbsSliderValue(0, color.getHue());
- setAbsSliderValue(1, color.getSaturation());
- setAbsSliderValue(2, color.getValue());
+ setAbsSliderValue(0, int(color.getHue()));
+ setAbsSliderValue(1, int(color.getSaturation()));
+ setAbsSliderValue(2, int(color.getValue()));
setAbsSliderValue(3, color.getAlpha());
}
diff --git a/src/app/ui/color_spectrum.cpp b/src/app/ui/color_spectrum.cpp
index 2e59bd3..9e87e1e 100644
--- a/src/app/ui/color_spectrum.cpp
+++ b/src/app/ui/color_spectrum.cpp
@@ -1,5 +1,5 @@
// Aseprite
-// Copyright (C) 2001-2015 David Capello
+// Copyright (C) 2001-2016 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
@@ -60,14 +60,14 @@ app::Color ColorSpectrum::pickColor(const gfx::Point& pos) const
umax = MAX(1, rc.h-1);
}
- int hue = 360 * u / umax;
- int sat = (v < vmid ? 100 * v / vmid : 100);
- int val = (v < vmid ? 100 : 100-(100 * (v-vmid) / vmid));
+ double hue = 360.0 * u / umax;
+ double sat = (v < vmid ? 100.0 * v / vmid : 100.0);
+ double val = (v < vmid ? 100.0 : 100.0-(100.0 * (v-vmid) / vmid));
return app::Color::fromHsv(
- MID(0, hue, 360),
- MID(0, sat, 100),
- MID(0, val, 100));
+ MID(0.0, hue, 360.0),
+ MID(0.0, sat, 100.0),
+ MID(0.0, val, 100.0));
}
void ColorSpectrum::selectColor(const app::Color& color)
@@ -116,32 +116,32 @@ void ColorSpectrum::onPaint(ui::PaintEvent& ev)
umax = MAX(1, rc.h-1);
}
- int hue = 360 * u / umax;
- int sat = (v < vmid ? 100 * v / vmid : 100);
- int val = (v < vmid ? 100 : 100-(100 * (v-vmid) / vmid));
+ double hue = 360.0 * u / umax;
+ double sat = (v < vmid ? 100.0 * v / vmid : 100.0);
+ double val = (v < vmid ? 100.0 : 100.0-(100.0 * (v-vmid) / vmid));
gfx::Color color = color_utils::color_for_ui(
app::Color::fromHsv(
- MID(0, hue, 360),
- MID(0, sat, 100),
- MID(0, val, 100)));
+ MID(0.0, hue, 360.0),
+ MID(0.0, sat, 100.0),
+ MID(0.0, val, 100.0)));
g->putPixel(color, rc.x+x, rc.y+y);
}
}
if (m_color.getType() != app::Color::MaskType) {
- int hue = m_color.getHue();
- int sat = m_color.getSaturation();
- int val = m_color.getValue();
- int lit = (200 - sat) * val / 200;
- gfx::Point pos(rc.x + hue * rc.w / 360,
- rc.y + rc.h - (lit * rc.h / 100));
+ double hue = m_color.getHue();
+ double sat = m_color.getSaturation();
+ double val = m_color.getValue();
+ double lit = (200.0 - sat) * val / 200.0;
+ gfx::Point pos(rc.x + int(hue * rc.w / 360.0),
+ rc.y + rc.h - int(lit * rc.h / 100.0));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawColoredRgbaSurface(
icon,
- lit > 50 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
+ lit > 50.0 ? gfx::rgba(0, 0, 0): gfx::rgba(255, 255, 255),
pos.x-icon->width()/2,
pos.y-icon->height()/2);
}
diff --git a/src/app/ui/color_wheel.cpp b/src/app/ui/color_wheel.cpp
index cfcca94..a8c5835 100644
--- a/src/app/ui/color_wheel.cpp
+++ b/src/app/ui/color_wheel.cpp
@@ -132,7 +132,7 @@ app::Color ColorWheel::pickColor(const gfx::Point& pos) const
boxsize, boxsize).contains(pos)) {
m_harmonyPicked = true;
- color = app::Color::fromHsv(convertHueAngle(color.getHue(), 1),
+ color = app::Color::fromHsv(convertHueAngle(int(color.getHue()), 1),
color.getSaturation(),
color.getValue());
return color;
@@ -186,10 +186,10 @@ app::Color ColorWheel::getColorInHarmony(int j) const
{
int i = MID(0, (int)m_harmony, (int)Harmony::LAST);
j = MID(0, j, harmonies[i].n-1);
- int hue = convertHueAngle(m_mainColor.getHue(), -1) + harmonies[i].hues[j];
- int sat = m_mainColor.getSaturation() * harmonies[i].sats[j] / 100;
- return app::Color::fromHsv(hue % 360,
- MID(0, sat, 100),
+ double hue = convertHueAngle(int(m_mainColor.getHue()), -1) + harmonies[i].hues[j];
+ double sat = m_mainColor.getSaturation() * harmonies[i].sats[j] / 100.0;
+ return app::Color::fromHsv(std::fmod(hue, 360),
+ MID(0.0, sat, 100.0),
m_mainColor.getValue());
}
@@ -253,17 +253,17 @@ void ColorWheel::onPaint(ui::PaintEvent& ev)
for (int i=0; i<n; ++i) {
app::Color color = getColorInHarmony(i);
- int angle = color.getHue()-30;
- int dist = color.getSaturation();
+ double angle = color.getHue()-30.0;
+ double dist = color.getSaturation();
- color = app::Color::fromHsv(convertHueAngle(color.getHue(), 1),
+ color = app::Color::fromHsv(convertHueAngle(int(color.getHue()), 1),
color.getSaturation(),
color.getValue());
gfx::Point pos =
m_wheelBounds.center() +
- gfx::Point(int(+std::cos(PI*angle/180)*double(m_wheelRadius)*dist/100.0),
- int(-std::sin(PI*angle/180)*double(m_wheelRadius)*dist/100.0));
+ gfx::Point(int(+std::cos(PI*angle/180.0)*double(m_wheelRadius)*dist/100.0),
+ int(-std::sin(PI*angle/180.0)*double(m_wheelRadius)*dist/100.0));
she::Surface* icon = theme->parts.colorWheelIndicator()->bitmap(0);
g->drawRgbaSurface(icon,
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git
More information about the Pkg-games-commits
mailing list