[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