]> git.imager.perl.org - imager.git/blob - color.c
[perl #101682] speed up color filled circle calculations
[imager.git] / color.c
1 #include "imager.h"
2 #include <math.h>
3
4 /*
5 =head1 NAME
6
7 color.c - color manipulation functions
8
9 =head1 SYNOPSIS
10
11   i_fcolor color;
12   i_rgb_to_hsvf(&color);
13   i_hsv_to_rgbf(&color);
14
15 =head1 DESCRIPTION
16
17 A collection of utility functions for converting between color spaces.
18
19 =over
20
21 =cut
22 */
23
24 #define EPSILON (1e-8)
25
26 #define my_max(a, b) ((a) < (b) ? (b) : (a))
27 #define my_min(a, b) ((a) > (b) ? (b) : (a))
28
29 /*
30 =item i_rgb2hsvf(&color)
31
32 Converts the first 3 channels of color into hue, saturation and value.
33
34 Each value is scaled into the range 0 to 1.0.
35
36 =cut
37 */
38 void i_rgb_to_hsvf(i_fcolor *color) {
39   double h = 0, s, v;
40   double temp;
41   double Cr, Cg, Cb;
42
43   v = my_max(my_max(color->rgb.r, color->rgb.g), color->rgb.b);
44   temp = my_min(my_min(color->rgb.r, color->rgb.g), color->rgb.b);
45   if (v < EPSILON)
46     s = 0;
47   else
48     s = (v-temp)/v;
49   if (s == 0)
50     h = 0;
51   else {
52     Cr = (v - color->rgb.r)/(v-temp);
53     Cg = (v - color->rgb.g)/(v-temp);
54     Cb = (v - color->rgb.b)/(v-temp);
55     if (color->rgb.r == v)
56       h = Cb - Cg;
57     else if (color->rgb.g == v)
58       h = 2 + Cr - Cb;
59     else if (color->rgb.b == v)
60       h = 4 + Cg - Cr;
61     h = 60 * h;
62     if (h < 0)
63       h += 360;
64   }
65   color->channel[0] = h / 360.0;
66   color->channel[1] = s;
67   color->channel[2] = v;
68 }
69
70 /*
71 =item i_rgb2hsv(&color)
72
73 Converts the first 3 channels of color into hue, saturation and value.
74
75 Each value is scaled into the range 0 to 255.
76
77 =cut
78 */
79 void i_rgb_to_hsv(i_color *color) {
80   double h = 0, s, v;
81   double temp;
82   double Cr, Cg, Cb;
83
84   v = my_max(my_max(color->rgb.r, color->rgb.g), color->rgb.b);
85   temp = my_min(my_min(color->rgb.r, color->rgb.g), color->rgb.b);
86   if (v == 0)
87     s = 0;
88   else
89     s = (v-temp)*255/v;
90   if (s == 0)
91     h = 0;
92   else {
93     Cr = (v - color->rgb.r)/(v-temp);
94     Cg = (v - color->rgb.g)/(v-temp);
95     Cb = (v - color->rgb.b)/(v-temp);
96     if (color->rgb.r == v)
97       h = Cb - Cg;
98     else if (color->rgb.g == v)
99       h = 2 + Cr - Cb;
100     else if (color->rgb.b == v)
101       h = 4 + Cg - Cr;
102     h = h * 60.0;
103     if (h < 0)
104       h += 360;
105   }
106   color->channel[0] = h * 255 / 360.0;
107   color->channel[1] = s;
108   color->channel[2] = v;
109 }
110
111 /*
112 =item i_hsv_to_rgbf(&color)
113
114 Convert a HSV value to an RGB value, each value ranges from 0 to 1.
115
116 =cut
117 */
118
119 void i_hsv_to_rgbf(i_fcolor *color) {
120   double h = color->channel[0];
121   double s = color->channel[1];
122   double v = color->channel[2];
123
124   if (color->channel[1] < EPSILON) {
125     /* ignore h in this case */
126     color->rgb.r = color->rgb.g = color->rgb.b = v;
127   }
128   else {
129     int i;
130     double f, m, n, k;
131     h = fmod(h, 1.0) * 6;
132     i = floor(h);
133     f = h - i;
134     m = v * (1 - s);
135     n = v * (1 - s * f);
136     k = v * (1 - s * (1 - f));
137     switch (i) {
138     case 0:
139       color->rgb.r = v; color->rgb.g = k; color->rgb.b = m;
140       break;
141     case 1:
142       color->rgb.r = n; color->rgb.g = v; color->rgb.b = m;
143       break;
144     case 2:
145       color->rgb.r = m; color->rgb.g = v; color->rgb.b = k;
146       break;
147     case 3:
148       color->rgb.r = m; color->rgb.g = n; color->rgb.b = v;
149       break;
150     case 4:
151       color->rgb.r = k; color->rgb.g = m; color->rgb.b = v;
152       break;
153     case 5:
154       color->rgb.r = v; color->rgb.g = m; color->rgb.b = n;
155       break;
156     }
157   }
158 }
159
160 /*
161 =item i_hsv_to_rgb(&color)
162
163 Convert a HSV value to an RGB value, each value ranges from 0 to 1.
164
165 =cut
166 */
167
168 void i_hsv_to_rgb(i_color *color) {
169   double h = color->channel[0];
170   double s = color->channel[1];
171   double v = color->channel[2];
172
173   if (color->channel[1] == 0) {
174     /* ignore h in this case */
175     color->rgb.r = color->rgb.g = color->rgb.b = v;
176   }
177   else {
178     int i;
179     double f;
180     int m, n, k;
181     h = h / 255.0 * 6;
182     i = h;
183     f = h - i;
184     m = 0.5 + v * (255 - s) / 255;
185     n = 0.5 + v * (255 - s * f) / 255;
186     k = 0.5 + v * (255 - s * (1 - f)) / 255;
187     switch (i) {
188     case 0:
189       color->rgb.r = v; color->rgb.g = k; color->rgb.b = m;
190       break;
191     case 1:
192       color->rgb.r = n; color->rgb.g = v; color->rgb.b = m;
193       break;
194     case 2:
195       color->rgb.r = m; color->rgb.g = v; color->rgb.b = k;
196       break;
197     case 3:
198       color->rgb.r = m; color->rgb.g = n; color->rgb.b = v;
199       break;
200     case 4:
201       color->rgb.r = k; color->rgb.g = m; color->rgb.b = v;
202       break;
203     case 5:
204       color->rgb.r = v; color->rgb.g = m; color->rgb.b = n;
205       break;
206     }
207   }
208 }
209
210 /*
211 =back
212
213 =head1 AUTHOR
214
215 Tony Cook <tony@develop-help.com>
216
217 =head1 SEE ALSO
218
219 Imager
220
221 =cut
222 */