]> git.imager.perl.org - imager.git/blame - color.c
allow imcover to use a non-default perl
[imager.git] / color.c
CommitLineData
92bda632 1#include "imager.h"
efdc2568 2#include <math.h>
6607600c
TC
3
4/*
5=head1 NAME
6
7color.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
17A 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
32Converts the first 3 channels of color into hue, saturation and value.
33
34Each value is scaled into the range 0 to 1.0.
35
36=cut
37*/
38void 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
73Converts the first 3 channels of color into hue, saturation and value.
74
75Each value is scaled into the range 0 to 255.
76
77=cut
78*/
79void 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
114Convert a HSV value to an RGB value, each value ranges from 0 to 1.
115
116=cut
117*/
118
119void 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
163Convert a HSV value to an RGB value, each value ranges from 0 to 1.
164
165=cut
166*/
167
168void 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
215Tony Cook <tony@develop-help.com>
216
217=head1 SEE ALSO
218
219Imager
220
221=cut
222*/