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