avoid a possible sign-extension for offsets/sizes in SGI
[imager.git] / color.c
diff --git a/color.c b/color.c
index 6097cc9..634a6c8 100644 (file)
--- a/color.c
+++ b/color.c
@@ -1,4 +1,5 @@
-#include "image.h"
+#include "imager.h"
+#include <math.h>
 
 /*
 =head1 NAME
@@ -15,10 +16,16 @@ color.c - color manipulation functions
 
 A collection of utility functions for converting between color spaces.
 
+=over
+
+=cut
 */
 
 #define EPSILON (1e-8)
 
+#define my_max(a, b) ((a) < (b) ? (b) : (a))
+#define my_min(a, b) ((a) > (b) ? (b) : (a))
+
 /*
 =item i_rgb2hsvf(&color)
 
@@ -29,12 +36,12 @@ Each value is scaled into the range 0 to 1.0.
 =cut
 */
 void i_rgb_to_hsvf(i_fcolor *color) {
-  double h, s, v;
+  double h = 0, s, v;
   double temp;
   double Cr, Cg, Cb;
 
-  v = max(max(color->rgb.r, color->rgb.g), color->rgb.b);
-  temp = min(min(color->rgb.r, color->rgb.g), color->rgb.b);
+  v = my_max(my_max(color->rgb.r, color->rgb.g), color->rgb.b);
+  temp = my_min(my_min(color->rgb.r, color->rgb.g), color->rgb.b);
   if (v < EPSILON)
     s = 0;
   else
@@ -60,6 +67,47 @@ void i_rgb_to_hsvf(i_fcolor *color) {
   color->channel[2] = v;
 }
 
+/*
+=item i_rgb2hsv(&color)
+
+Converts the first 3 channels of color into hue, saturation and value.
+
+Each value is scaled into the range 0 to 255.
+
+=cut
+*/
+void i_rgb_to_hsv(i_color *color) {
+  double h = 0, s, v;
+  double temp;
+  double Cr, Cg, Cb;
+
+  v = my_max(my_max(color->rgb.r, color->rgb.g), color->rgb.b);
+  temp = my_min(my_min(color->rgb.r, color->rgb.g), color->rgb.b);
+  if (v == 0)
+    s = 0;
+  else
+    s = (v-temp)*255/v;
+  if (s == 0)
+    h = 0;
+  else {
+    Cr = (v - color->rgb.r)/(v-temp);
+    Cg = (v - color->rgb.g)/(v-temp);
+    Cb = (v - color->rgb.b)/(v-temp);
+    if (color->rgb.r == v)
+      h = Cb - Cg;
+    else if (color->rgb.g == v)
+      h = 2 + Cr - Cb;
+    else if (color->rgb.b == v)
+      h = 4 + Cg - Cr;
+    h = h * 60.0;
+    if (h < 0)
+      h += 360;
+  }
+  color->channel[0] = h * 255 / 360.0;
+  color->channel[1] = s;
+  color->channel[2] = v;
+}
+
 /*
 =item i_hsv_to_rgbf(&color)
 
@@ -81,7 +129,7 @@ void i_hsv_to_rgbf(i_fcolor *color) {
     int i;
     double f, m, n, k;
     h = fmod(h, 1.0) * 6;
-    i = h;
+    i = floor(h);
     f = h - i;
     m = v * (1 - s);
     n = v * (1 - s * f);
@@ -109,6 +157,56 @@ void i_hsv_to_rgbf(i_fcolor *color) {
   }
 }
 
+/*
+=item i_hsv_to_rgb(&color)
+
+Convert a HSV value to an RGB value, each value ranges from 0 to 1.
+
+=cut
+*/
+
+void i_hsv_to_rgb(i_color *color) {
+  double h = color->channel[0];
+  double s = color->channel[1];
+  double v = color->channel[2];
+
+  if (color->channel[1] == 0) {
+    /* ignore h in this case */
+    color->rgb.r = color->rgb.g = color->rgb.b = v;
+  }
+  else {
+    int i;
+    double f;
+    int m, n, k;
+    h = h / 255.0 * 6;
+    i = h;
+    f = h - i;
+    m = 0.5 + v * (255 - s) / 255;
+    n = 0.5 + v * (255 - s * f) / 255;
+    k = 0.5 + v * (255 - s * (1 - f)) / 255;
+    switch (i) {
+    case 0:
+      color->rgb.r = v; color->rgb.g = k; color->rgb.b = m;
+      break;
+    case 1:
+      color->rgb.r = n; color->rgb.g = v; color->rgb.b = m;
+      break;
+    case 2:
+      color->rgb.r = m; color->rgb.g = v; color->rgb.b = k;
+      break;
+    case 3:
+      color->rgb.r = m; color->rgb.g = n; color->rgb.b = v;
+      break;
+    case 4:
+      color->rgb.r = k; color->rgb.g = m; color->rgb.b = v;
+      break;
+    case 5:
+      color->rgb.r = v; color->rgb.g = m; color->rgb.b = n;
+      break;
+    }
+  }
+}
+
 /*
 =back