Commit | Line | Data |
---|---|---|
92bda632 | 1 | #include "imager.h" |
efdc2568 | 2 | #include <math.h> |
6607600c TC |
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 | ||
12db268a TC |
19 | =over |
20 | ||
21 | =cut | |
6607600c TC |
22 | */ |
23 | ||
24 | #define EPSILON (1e-8) | |
25 | ||
efdc2568 TC |
26 | #define my_max(a, b) ((a) < (b) ? (b) : (a)) |
27 | #define my_min(a, b) ((a) > (b) ? (b) : (a)) | |
28 | ||
6607600c TC |
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) { | |
e4bf9335 | 39 | double h = 0, s, v; |
6607600c TC |
40 | double temp; |
41 | double Cr, Cg, Cb; | |
42 | ||
efdc2568 TC |
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); | |
6607600c TC |
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 | ||
efdc2568 TC |
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) { | |
e4bf9335 | 80 | double h = 0, s, v; |
efdc2568 TC |
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 | ||
6607600c TC |
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; | |
efdc2568 | 132 | i = floor(h); |
6607600c TC |
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 | ||
efdc2568 TC |
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; | |
87039ee8 TC |
179 | double f; |
180 | int m, n, k; | |
efdc2568 TC |
181 | h = h / 255.0 * 6; |
182 | i = h; | |
183 | f = h - i; | |
87039ee8 TC |
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; | |
efdc2568 TC |
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 | ||
6607600c TC |
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 | */ |