File Coverage

color_space.c
Criterion Covered Total %
statement 163 188 86.7
branch 91 112 81.2
condition n/a
subroutine n/a
pod n/a
total 254 300 84.6


line stmt bran cond sub pod time code
1             #include
2             #include
3             /* Needed this to compile on strawberry-perl-5.40.0.1-64bit-PDL */
4             #ifndef M_PI
5             #define M_PI 3.14159265358979323846
6             #endif
7              
8             #define epsilon 0.008856
9             #define kappa 903.3
10              
11             struct pixel {
12             double a;
13             double b;
14             double c;
15             };
16              
17             #include "color_space.h" /* Local decs */
18              
19             /*** util functions ***/
20 62           double _apow (double a, double p) {
21 62 50         return pow(a >= 0.0 ? a : -a, p);
22             }
23             #define EXTREME(var, a, b, c, cmp) \
24             double var = a; \
25             if (b cmp var) var = b; \
26             if (c cmp var) var = c
27             #define BOUNDED(v, min, max) while (v < min) v += max;while (v >= max) v -= max
28             #define CALC_HS(h, s, max, delta, r, g, b, satscale) \
29             /* set up a greyscale if rgb values are identical */ \
30             /* Note: automatically includes max = 0 */ \
31             if (delta <= 0.0) { \
32             h = s = 0; \
33             return; \
34             } \
35             s = delta / satscale; \
36             h = (r == max) ? (g - b) / delta : \
37             (g == max) ? 2 + (b - r) / delta : \
38             4 + (r - g) / delta; \
39             h *= 60.0; \
40             BOUNDED(h, 0, 360)
41 9           double _rad2deg( double rad )
42             {
43 9           return 180.0 * rad / M_PI;
44             }
45 5           double _deg2rad( double deg )
46             {
47 5           return deg * (M_PI / 180.0);
48             }
49 30           void _mult_v3_m33( struct pixel *p, double *m0, double *m1, double *m2, double *result )
50             {
51 30           result[0] = p->a * m0[0] + p->b * m1[0] + p->c * m2[0];
52 30           result[1] = p->a * m0[1] + p->b * m1[1] + p->c * m2[1];
53 30           result[2] = p->a * m0[2] + p->b * m1[2] + p->c * m2[2];
54 30           }
55              
56             /* ~~~~~~~~~~:> */
57              
58 21           double rgb_quant( double p, double q, double h )
59             {
60 27 100         BOUNDED(h, 0, 360);
    100          
61 21 100         if (h < 60) { return p + (q-p)*h/60; }
62 17 100         else if (h < 180) { return q; }
63 10 100         else if (h < 240) { return p + (q-p)*(240-h)/60; }
64 7           else { return p; }
65             }
66              
67              
68 7           void rgb2cmyk( double *rgb, double *cmyk )
69             {
70 7           struct pixel cmy = { 1.0-rgb[0], 1.0-rgb[1], 1.0-rgb[2] };
71              
72 7 100         EXTREME(k, cmy.a, cmy.b, cmy.c, <);
    100          
73              
74 7           cmyk[0] = cmy.a - k;
75 7           cmyk[1] = cmy.b - k;
76 7           cmyk[2] = cmy.c - k;
77 7           cmyk[3] = k;
78 7           }
79              
80              
81 7           void cmyk2rgb( double *cmyk, double *rgb )
82             {
83 7           double k = cmyk[3];
84 7           rgb[0] = 1.0 - cmyk[0] - k;
85 7           rgb[1] = 1.0 - cmyk[1] - k;
86 7           rgb[2] = 1.0 - cmyk[2] - k;
87 7           }
88              
89              
90 7           void hsl2rgb( double *hsl, double *rgb )
91             {
92 7           double h = hsl[0];
93 7           double s = hsl[1];
94 7           double l = hsl[2];
95              
96             double p, q;
97              
98 7 100         if ( l <= 0.5) {
99 3           p = l*(1 - s);
100 3           q = 2*l - p;
101             }
102             else {
103 4           q = l + s - (l*s);
104 4           p = 2*l - q;
105             }
106              
107 7           rgb[0] = rgb_quant(p, q, h+120);
108 7           rgb[1] = rgb_quant(p, q, h);
109 7           rgb[2] = rgb_quant(p, q, h-120);
110 7           }
111              
112              
113 7           void rgb2hsl( double *rgb, double *hsl )
114             {
115 7           double r = rgb[0];
116 7           double g = rgb[1];
117 7           double b = rgb[2];
118             /* compute the min and max */
119 7 100         EXTREME(max, r, g, b, >);
    100          
120 7 100         EXTREME(min, r, g, b, <);
    50          
121 7           double delta = max - min;
122 7           double sum = max + min;
123             /* luminance */
124 7           hsl[2] = sum / 2.0;
125 8 100         CALC_HS(hsl[0], hsl[1], max, delta, r, g, b, (hsl[2] <= 0.5 ? sum : (2.0 - sum)));
    100          
    100          
    50          
    100          
    50          
126             }
127              
128              
129 7           void rgb2hsv( double *rgb, double *hsv )
130             {
131 7           double r = rgb[0];
132 7           double g = rgb[1];
133 7           double b = rgb[2];
134             /* compute the min and max */
135 7 100         EXTREME(max, r, g, b, >);
    100          
136 7 100         EXTREME(min, r, g, b, <);
    50          
137             /* got V */
138 7           hsv[2] = max;
139 7           double delta = max - min;
140 8 100         CALC_HS(hsv[0], hsv[1], max, delta, r, g, b, max);
    100          
    50          
    100          
    50          
141             }
142              
143              
144 7           void hsv2rgb( double *hsv, double *rgb )
145             {
146 7           double h = hsv[0];
147 7           double s = hsv[1];
148 7           double v = hsv[2];
149              
150 7           h /= 60.0;
151 7           double i = floor( h );
152 7           double f = h - i;
153              
154 7           double p = v * (1 - s);
155 7           double q = v * (1 - s * f);
156 7           double t = v * (1 - s * (1 - f));
157              
158 7           switch( (int) i )
159             {
160 4           case 0:
161 4           rgb[0] = v;
162 4           rgb[1] = t;
163 4           rgb[2] = p;
164 4           break;
165 0           case 1:
166 0           rgb[0] = q;
167 0           rgb[1] = v;
168 0           rgb[2] = p;
169 0           break;
170 0           case 2:
171 0           rgb[0] = p;
172 0           rgb[1] = v;
173 0           rgb[2] = t;
174 0           break;
175 1           case 3:
176 1           rgb[0] = p;
177 1           rgb[1] = q;
178 1           rgb[2] = v;
179 1           break;
180 0           case 4:
181 0           rgb[0] = t;
182 0           rgb[1] = p;
183 0           rgb[2] = v;
184 0           break;
185 2           default:
186 2           rgb[0] = v;
187 2           rgb[1] = p;
188 2           rgb[2] = q;
189 2           break;
190             }
191 7           }
192              
193              
194 20           void rgb2xyz( double *rgb, double gamma, double *m0, double *m1, double *m2, double *xyz )
195             {
196 20           rgb2linear(rgb, gamma, xyz);
197 20           struct pixel p = { xyz[0], xyz[1], xyz[2] };
198 20           _mult_v3_m33( &p, m0, m1, m2, xyz );
199 20           }
200              
201              
202 24           void rgb2linear( double *rgb, double gamma, double *out )
203             {
204             int i;
205 24 100         if (gamma < 0) { /* special case for sRGB gamma curve */
206 56 100         for (i = 0; i < 3; i++)
207 42 100         out[i] = fabs(rgb[i]) <= 0.04045 ? rgb[i] / 12.92 : _apow( (rgb[i] + 0.055)/1.055, 2.4 );
208 10 100         } else if (gamma == 1.0) { /* copy if different locations */
209 4 50         if (rgb != out)
210 16 100         for (i = 0; i < 3; i++)
211 12           out[i] = rgb[i];
212             } else {
213 24 100         for (i = 0; i < 3; i++)
214 18           out[i] = _apow(rgb[i], gamma);
215             }
216 24           }
217              
218              
219 10           void xyz2rgb( double *xyz, double gamma, double *m0, double *m1, double *m2, double *rgb )
220             {
221 10           struct pixel p = { xyz[0], xyz[1], xyz[2] };
222 10           _mult_v3_m33( &p, m0, m1, m2, rgb );
223 10           rgb2gamma(rgb, gamma, rgb);
224 10           }
225              
226              
227 14           void rgb2gamma( double *rgb, double gamma, double *out )
228             {
229             int i;
230 14 50         if (gamma < 0) { /* special case for sRGB gamma curve */
231 56 100         for (i = 0; i < 3; i++)
232 42 100         out[i] = (fabs(rgb[i]) <= 0.0031308) ? 12.92 * rgb[i] : 1.055 * _apow(rgb[i], 1.0/2.4) - 0.055;
233 0 0         } else if (gamma == 1.0) { /* copy if different locations */
234 0 0         if (rgb != out)
235 0 0         for (i = 0; i < 3; i++)
236 0           out[i] = rgb[i];
237             } else {
238 0 0         for (i = 0; i < 3; i++)
239 0           out[i] = _apow(rgb[i], 1.0 / gamma);
240             }
241 14           }
242              
243              
244 16           void xyY2xyz( double *xyY, double *xyz )
245             {
246 16 50         if ( xyY[1] == 0.0 ) {
247 0           xyz[0] = xyz[1] = xyz[2] = 0.0;
248 0           return;
249             }
250 16           xyz[0] = xyY[0] / xyY[1];
251 16           xyz[1] = 1.0;
252 16           xyz[2] = (1.0 - xyY[0] - xyY[1]) / xyY[1];
253             }
254              
255              
256 13           void xyz2lab( double *xyz, double *w, double *lab )
257             {
258 13           double xr = xyz[0] / w[0];
259 13           double yr = xyz[1] / w[1];
260 13           double zr = xyz[2] / w[2];
261              
262 13 100         double fx = (xr > epsilon)? pow(xr, 1.0/3.0) : (kappa * xr + 16.0) / 116.0;
263 13 100         double fy = (yr > epsilon)? pow(yr, 1.0/3.0) : (kappa * yr + 16.0) / 116.0;
264 13 100         double fz = (zr > epsilon)? pow(zr, 1.0/3.0) : (kappa * zr + 16.0) / 116.0;
265              
266 13           lab[0] = 116.0 * fy - 16.0;
267 13           lab[1] = 500.0 * (fx - fy);
268 13           lab[2] = 200.0 * (fy - fz);
269 13           }
270              
271 9           void lab2lch( double *lab, double *lch )
272             {
273 9           lch[0] = lab[0];
274 9           lch[1] = sqrt( pow(lab[1], 2) + pow(lab[2], 2) );
275 9           lch[2] = _rad2deg( atan2( lab[2], lab[1] ) );
276              
277 16 100         BOUNDED(lch[2], 0.0, 360.0);
    50          
278 9           }
279              
280 5           void lch2lab( double *lch, double *lab )
281             {
282             /* l is set */
283 5           lab[0] = lch[0];
284              
285 5           double c = lch[1];
286 5           double h = _deg2rad( lch[2] );
287 5           double th = tan(h);
288              
289 5           double *a = lab+1;
290 5           double *b = lab+2;
291              
292 5           *a = c / sqrt( pow(th,2) + 1 );
293 5           *b = sqrt( pow(c, 2) - pow(*a, 2) );
294              
295 5 50         if (h < 0.0)
296 0           h += 2*M_PI;
297 5 100         if (h > M_PI/2 && h < M_PI*3/2)
    50          
298 0           *a = -*a;
299 5 100         if (h > M_PI)
300 3           *b = -*b;
301 5           }
302              
303              
304 11           void lab2xyz( double *lab, double *w, double *xyz )
305             {
306 11 100         double yr = (lab[0] > kappa * epsilon) ? pow( (lab[0] + 16.0)/116.0, 3 ) : lab[0] / kappa;
307              
308 11 100         double fy = (yr > epsilon) ? (lab[0] + 16.0)/116.0 : (kappa * yr + 16.0)/116.0;
309 11           double fx = fy + lab[1] / 500.0;
310 11           double fz = fy - lab[2] / 200.0;
311              
312 11 100         double xr = (pow(fx, 3) > epsilon) ? pow(fx, 3) : (fx * 116.0 - 16.0) / kappa;
313 11 100         double zr = (pow(fz, 3) > epsilon) ? pow(fz, 3) : (fz * 116.0 - 16.0) / kappa;
314              
315 11           xyz[0] = xr * w[0];
316 11           xyz[1] = yr * w[1];
317 11           xyz[2] = zr * w[2];
318 11           }