File Coverage

lib/Colouring/In/XS.xs
Criterion Covered Total %
statement 373 414 90.1
branch 182 264 68.9
condition n/a
subroutine n/a
pod n/a
total 555 678 81.8


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT // we'll define thread context if necessary (faster)
2             #include "EXTERN.h" // globals/constant import locations
3             #include "perl.h" // Perl symbols, structures and constants definition
4             #include "XSUB.h" // xsubpp functions and macros
5             #include // rand()
6             #include
7              
8             struct HS {
9             double r;
10             double g;
11             double b;
12             double max;
13             double min;
14             double d;
15             double h;
16             double s;
17             double l;
18             double v;
19             };
20              
21             struct HSL {
22             int h;
23             double s;
24             double l;
25             double a;
26             };
27              
28             static HV * MESSAGES;
29              
30 10153           static SV * new (SV * class, HV * hash) {
31             dTHX;
32 10153 100         if (SvTYPE(class) != SVt_PV) {
33 2 50         char * name = HvNAME(SvSTASH(SvRV(class)));
    50          
    50          
    0          
    50          
    50          
34 2           class = newSVpv(name, strlen(name));
35             }
36 10153           return sv_bless(newRV_noinc((SV*)hash), gv_stashsv(class, 0));
37             }
38              
39 10206           static AV * colour_array (SV * self) {
40             dTHX;
41 10206           AV * colour = (AV*)SvRV(*hv_fetch((HV*)SvRV(self), "colour", 6, 0));
42              
43 10206           SV * r = *av_fetch(colour, 0, 0);
44 10206           SV * g = *av_fetch(colour, 1, 0);
45 10206           SV * b = *av_fetch(colour, 2, 0);
46              
47 10206 100         if ( !SvOK(r) ) {
48 1           av_store(colour, 0, newSVnv(255));
49             }
50              
51 10206 100         if ( !SvOK(g) ) {
52 1           av_store(colour, 1, newSVnv(255));
53             }
54              
55 10206 100         if ( !SvOK(b) ) {
56 1           av_store(colour, 2, newSVnv(255));
57             }
58              
59 10206           return colour;
60             }
61              
62 3           void croak_message (char * key, char * fb) {
63             dTHX;
64 3 50         if (hv_exists(MESSAGES, key, strlen(key))) {
65 0           SV * msg = *hv_fetch(MESSAGES, key, strlen(key), 0);
66 0 0         if (SvTRUE(msg)) {
67 0           fb = SvPV_nolen(msg);
68             }
69             }
70 3           croak("%s", fb);
71             }
72              
73 30463           static double min (double first, double second) {
74 30463 100         return first < second ? first : second;
75             }
76              
77 30463           static double max (double first, double second) {
78 30463 100         return first > second ? first : second;
79             }
80              
81 30279           static double clamp (double first, double second) {
82 30279           return min( max(first, 0), second);
83             }
84              
85 17           static double rround (double val, int dp) {
86 17           int charsNeeded = 1 + snprintf(NULL, 0, "%.*f", dp, val);
87 17           char * buffer = malloc(charsNeeded);
88 17           snprintf(buffer, charsNeeded, "%.*f", dp, val);
89 17           double result = atof(buffer);
90 17           free(buffer);
91 17           return result;
92             }
93              
94 10162           static int numIs (SV * num) {
95             dTHX;
96 10162           char * str = SvPV_nolen(num);
97             char tmp[256];
98 10162 50         for(int i=0;str[i];i++) {
99 10162           int j=0;
100 20324 100         while(str[i]>='0' && str[i]<='9') {
    50          
101 10162           tmp[j]=str[i];
102 10162           i++;
103 10162           j++;
104             }
105 10162           break;
106             }
107 10162           return strlen(tmp) >= 1 ? 1 : 0;
108             }
109              
110 40           static char * percent (double num) {
111 40           char * ret = malloc(sizeof(char)*5);
112 40           sprintf(ret, "%.0f%s", (num * 100), "%");
113 40           return ret;
114             }
115              
116 65           static double depercent (char * num) {
117 65           return atof(num) / 100.;
118             }
119              
120 0           char* join(char* strings[], char* seperator, int count) {
121 0           char* str = NULL; /* Pointer to the joined strings */
122 0           size_t total_length = 0; /* Total length of joined strings */
123 0           int i = 0; /* Loop counter */
124              
125             /* Find total length of joined strings */
126 0 0         for (i = 0; i < count; i++) total_length += strlen(strings[i]);
127 0           total_length++; /* For joined string terminator */
128 0           total_length += strlen(seperator) * (count - 1); // for seperators
129              
130 0           str = (char*) malloc(total_length); /* Allocate memory for joined strings */
131 0           str[0] = '\0'; /* Empty string we can append to */
132              
133             /* Append all the strings */
134 0 0         for (i = 0; i < count; i++) {
135 0           strcat(str, strings[i]);
136 0 0         if (i < (count - 1)) strcat(str, seperator);
137             }
138              
139 0           return str;
140             }
141              
142 30210           static double hue (double h, double m1, double m2) {
143 30210 100         h = h < 0 ? h + 1 : h > 1 ? h - 1 : h;
    100          
144 30210 100         if ( h * 6. < 1 ) {
145 5059           return m1 + ( m2 - m1 ) * h * 6;
146 25151 100         } else if ( h * 2. < 1 ) {
147 10070           return m2;
148 15081 100         } else if ( h * 3. < 2 ) {
149 4983           return m1 + ( m2 - m1 ) * ( (2 / 3.) - h ) * 6;
150             }
151 10098           return m1;
152             }
153              
154 3           static double scaled (SV * num, int size) {
155             dTHX;
156 3           char * number = SvPV_nolen(num);
157 3           double n = atof(number);
158 3 50         if (number[strlen(number)] == '%') {
159 0           return (n * size) / 100;
160             } else {
161 3           return n;
162             }
163             }
164              
165 145           int hex2int(char *hex) {
166 145           int val = 0;
167 433 100         while (*hex) {
168 289           int byte = *hex++;
169 289 50         if (byte >= '0' && byte <= '9') byte = byte - '0';
    100          
170 217 50         else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
    100          
171 1 50         else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
    50          
172 1           else croak_message("INVALID_HEX", "Cannot convert hex colour format");
173 288           val = (val << 4) | (byte & 0xF);
174             }
175 144           return val;
176             }
177              
178 49           static SV * hex2rgb (char * colour) {
179             dTHX;
180 49           AV * color = newAV();
181 49           int l = strlen(colour);
182 49 100         if (l == 3) {
183 5 100         for (int i = 0; i < 3; i++) {
184 4           char * hex = malloc(sizeof(char)*22);
185 4           sprintf(hex, "%c%c", colour[i], colour[i]);
186 4           av_push(color, newSViv(hex2int(hex)));
187             }
188 47 50         } else if (l == 6) {
189 188 100         for (int i = 0; i < 6; i += 2) {
190 141           char * hex = malloc(sizeof(char)*22);;
191 141           sprintf(hex, "%c%c", colour[i], colour[i + 1]);
192 141           av_push(color, newSViv(hex2int(hex)));
193             }
194             } else {
195 0           croak("hex length must be 3 or 6");
196             }
197 48           return newRV_noinc((SV*)color);
198             }
199              
200 10023           static AV * numbers (char * colour) {
201             dTHX;
202 10023           AV * color = newAV();
203 10023           int len = strlen(colour);
204 10023           char temp[6] = "";
205 229338 100         for (int i = 0; i < len; i++) {
206 219315 100         if ((colour[i] >= '0' && colour[i] <= '9') || colour[i] == '.') {
    100          
    50          
207 99058           strncat(temp, &colour[i], 1);
208 120257 100         } else if (strlen(temp) >= 1 && atol(temp) >= 0) {
    50          
209 40076           av_push(color, newSVnv(atol(temp)));
210 40076           memset(temp,0,strlen(temp));
211             }
212             }
213              
214 10023 100         if (av_len(color) <= 1) {
215 2           croak_message("INVALID_RGB", "Cannot convert rgb colour format");
216             }
217              
218 10021           return color;
219             }
220              
221 19           static SV * rgb2rgb (char * colour) {
222             dTHX;
223 19           return newRV_noinc((SV*)numbers(colour));
224             }
225              
226 10070           static SV * hsl2rgb (double h, double s, double l, double a) {
227             dTHX;
228 10070           AV * color = newAV();
229 10070           int lame = (int)h;
230 10070           h = ( lame % 360 ) / 360.;
231 10070 100         if (s > 1 || l > 1) {
    50          
232 10001           s = s / 100.;
233 10001           l = l / 100.;
234             }
235 10070 100         double m2 = l <= 0.5 ? l * ( s + 1 ) : l + s - l * s;
236 10070           double m1 = l * 2 - m2;
237 10070           av_push(color, newSViv(clamp(hue(h + (1 / 3.), m1, m2), 1) * 255));
238 10070           av_push(color, newSViv(clamp(hue(h, m1, m2), 1) * 255));
239 10070           av_push(color, newSViv(clamp(hue(h - (1 / 3.), m1, m2), 1) * 255));
240 10070           return newRV_noinc((SV*)color);
241             }
242              
243 10072           static SV * convertColour (char * colour) {
244             dTHX;
245 10072 100         if (colour[0] == '#') {
246 49           colour++;
247 49           return hex2rgb(colour);
248 10023 100         } else if (colour[0] == 'r' && colour[1] == 'g' && colour[2] == 'b') {
    50          
    50          
249 19           return rgb2rgb(colour);
250 10004 50         } else if (colour[0] == 'h' && colour[1] == 's' && colour[2] == 'l') {
    50          
    50          
251 10004           AV * nums = numbers(colour);
252 10003           int len = av_len(nums);
253 10003 50         double h = len >= 0 ? SvNV(*av_fetch(nums, 0, 0)) : 0;
254 10003 50         double s = len >= 1 ? SvNV(*av_fetch(nums, 1, 0)) : 0;
255 10003 50         double l = len >= 2 ? SvNV(*av_fetch(nums, 2, 0)) : 0;
256 10003 100         double a = len >= 3 ? SvNV(*av_fetch(nums, 3, 0)) : 1;
257 10003           return hsl2rgb(h, s, l, a);
258             }
259 0           croak_message("INVALID_COLOUR", "Cannot convert the colour format");
260 0           return newSVpv("never", 5);
261             }
262              
263 46           static void sprintf_colour (SV * self, char * css, char * pattern) {
264             dTHX;
265 46           int colour[3] = { 255, 255, 255 };
266 46           AV * color = colour_array(self);
267 46           int len = av_len(color);
268 46 50         colour[0] = len >= 0 ? SvIV(*av_fetch(color, 0, 0)) : 255;
269 46 50         colour[1] = len >= 1 ? SvIV(*av_fetch(color, 1, 0)) : 255;
270 46 50         colour[2] = len >= 2 ? SvIV(*av_fetch(color, 2, 0)) : 255;
271 46           sprintf(css, pattern, colour[0], colour[1], colour[2]);
272 46           }
273              
274 45           static void sprintf_rgba (SV * self, char * css) {
275             dTHX;
276 45           int colour[3] = { 255, 255, 255 };
277 45           AV * color = colour_array(self);
278 45           double alpha = SvNV(*hv_fetch((HV*)SvRV(self), "alpha", 5, 0));
279 45           int len = av_len(color);
280 45 50         colour[0] = len >= 0 ? SvIV(*av_fetch(color, 0, 0)) : 255;
281 45 50         colour[1] = len >= 1 ? SvIV(*av_fetch(color, 1, 0)) : 255;
282 45 50         colour[2] = len >= 2 ? SvIV(*av_fetch(color, 2, 0)) : 255;
283 45           sprintf(css, "rgba(%d,%d,%d,%.2g)", colour[0], colour[1], colour[2], alpha);
284 45           }
285              
286 92           static struct HS rgb2hs (SV * self) {
287             dTHX;
288             struct HS hs;
289 92           AV * color = colour_array(self);
290 92           int len = av_len(color);
291 92 50         hs.r = len >= 0 ? SvIV(*av_fetch(color, 0, 0)) / 255.00 : 1;
292 92 50         hs.g = len >= 1 ? SvIV(*av_fetch(color, 1, 0)) / 255.00 : 1;
293 92 50         hs.b = len >= 2 ? SvIV(*av_fetch(color, 2, 0)) / 255.00 : 1;
294 92           hs.max = max(max(hs.r, hs.g), hs.b);
295 92           hs.min = min(min(hs.r, hs.g), hs.b);
296 92           hs.d = hs.max - hs.min;
297 92           return hs;
298             }
299              
300 84           static struct HSL asHSL (SV * self) {
301             dTHX;
302 84           struct HS hs = rgb2hs(self);
303              
304 84           hs.l = ( hs.max + hs.min ) / 2;
305              
306 84 100         if ( hs.max == hs.min ) {
307 74           hs.h = hs.s = 0;
308             } else {
309 10 100         hs.s = hs.l > 0.5 ? (hs.d / (2 - hs.max - hs.min)) : (hs.d / (hs.max + hs.min));
310 20           hs.h = (hs.max == hs.r)
311 4 100         ? (hs.g - hs.b) / hs.d + ( hs.g < hs.b ? 6 : 0 )
312 20 100         : (hs.max == hs.g)
313 5           ? (hs.b - hs.r) / hs.d + 2
314 6 100         : (hs.r - hs.g) / hs.d + 4;
315 10           hs.h = hs.h / 6;
316             }
317              
318             struct HSL hsl;
319 84           hsl.h = hs.h * 360;
320 84           hsl.s = hs.s;
321 84           hsl.l = hs.l;
322 84           hsl.a = SvNV(*hv_fetch((HV*)SvRV(self), "alpha", 5, 0));
323 84           return hsl;
324             }
325              
326 10156           static SV * new_color (SV * class, SV * colour, SV * a) {
327             dTHX;
328 10156           HV * hash = newHV();
329 10156 100         if (SvTYPE(SvRV(colour)) == SVt_PVAV) {
330 84 50         if (av_len((AV*)colour) == 3) {
331 0           a = av_pop((AV*)colour);
332             }
333 84           hv_store(hash, "colour", 6, newSVsv(colour), 0);
334             } else {
335 10072           colour = convertColour(SvPV_nolen(colour));
336 10069 100         if (av_len((AV*)SvRV(colour)) == 3) {
337 11           a = av_pop((AV*)SvRV(colour));
338             }
339 10069           hv_store(hash, "colour", 6, colour, 0);
340             }
341 10153 50         hv_store(hash, "alpha", 5, numIs(a) ? newSVsv(a) : newSViv(1), 0);
342 10153           return new(class, hash);
343             }
344              
345 3           static SV * mix (SV * colour1, SV * colour2, int weight) {
346             dTHX;
347              
348 3           SV * class = newSVpv("Colouring::In::XS", 17);
349 3 50         if (SvTYPE(colour1) == SVt_PV) {
350 3           colour1 = new_color(class, colour1, newSVnv(1));
351             }
352 3 50         if (SvTYPE(colour2) == SVt_PV) {
353 3           colour2 = new_color(class, colour2, newSVnv(1));
354             }
355 3           struct HSL hsl1 = asHSL(colour1);
356 3           struct HSL hsl2 = asHSL(colour2);
357              
358 3           double w = weight / 100.;
359              
360 3           double a = hsl1.a - hsl2.a;
361              
362 3           w = (w * 2) - 1;
363 3 50         double w1 = (((w * a == -1) ? w : (w + a) / ( 1 + w * a )) + 1 ) / 2;
364 3           double w2 = 1 - w1;
365              
366 3           AV * c = newAV();
367              
368 3           AV * c1 = (AV*)SvRV(*hv_fetch((HV*)SvRV(colour1), "colour", 6, 0));
369 3           AV * c2 = (AV*)SvRV(*hv_fetch((HV*)SvRV(colour2), "colour", 6, 0));
370              
371 3           double r1 = SvNV(*av_fetch(c1, 0, 0));
372 3           double g1 = SvNV(*av_fetch(c1, 1, 0));
373 3           double b1 = SvNV(*av_fetch(c1, 2, 0));
374 3           double a1 = SvNV(*hv_fetch((HV*)SvRV(colour1), "alpha", 5, 0));
375              
376 3           double r2 = SvNV(*av_fetch(c2, 0, 0));
377 3           double g2 = SvNV(*av_fetch(c2, 1, 0));
378 3           double b2 = SvNV(*av_fetch(c2, 2, 0));
379 3           double a2 = SvNV(*hv_fetch((HV*)SvRV(colour2), "alpha", 5, 0));
380              
381            
382 3           av_push(c, newSVnv((r1 * w1) + (r2 * w2)));
383 3           av_push(c, newSVnv((g1 * w1) + (g2 * w2)));
384 3           av_push(c, newSVnv((b1 * w1) + (b2 * w2)));
385              
386 3           return new_color(class, newRV_noinc((SV*)c), newSVnv((a1 * w) + (a2 * 1 - w)));
387             }
388              
389              
390             MODULE = Colouring::In::XS PACKAGE = Colouring::In::XS
391             PROTOTYPES: ENABLE
392             FALLBACK: TRUE
393              
394             void
395             set_messages(...)
396             CODE:
397 1           AV * array = av_make(items, MARK+1);
398 1           MESSAGES = (HV*)SvRV(av_pop(array));
399              
400             SV *
401             new(...)
402             CODE:
403 10026           SV * colour = ST(1);
404 10026 100         SV * a = (items > 2) && SvOK(ST(2)) ? ST(2) : newSViv(1);
    100          
405 10026           RETVAL = new_color(ST(0), colour, a);
406             OUTPUT:
407             RETVAL
408              
409             SV *
410             rgb(self, red, green, blue, ...)
411             SV * self
412             SV * red
413             SV * green
414             SV * blue
415             CODE:
416 1           double r = scaled(red, 255);
417 1           double g = scaled(green, 255);
418 1           double b = scaled(blue, 255);
419 1           AV * colour = newAV();
420 1           av_push(colour, newSVnv(r));
421 1           av_push(colour, newSVnv(g));
422 1           av_push(colour, newSVnv(b));
423 1 50         double a = clamp(items > 4 ? SvNV(ST(4)) : 1, 1);
424 1           RETVAL = new_color(self, newRV_noinc((SV*)colour), newSVnv(a));
425             OUTPUT:
426             RETVAL
427              
428             SV *
429             rgba(self, red, green, blue, ...)
430             SV * self
431             SV * red
432             SV * green
433             SV * blue
434             CODE:
435 0           double r = scaled(red, 255);
436 0           double g = scaled(green, 255);
437 0           double b = scaled(blue, 255);
438 0           AV * colour = newAV();
439 0           av_push(colour, newSVnv(r));
440 0           av_push(colour, newSVnv(g));
441 0           av_push(colour, newSVnv(b));
442 0 0         double a = clamp(items > 4 ? SvNV(ST(4)) : 1, 1);
443 0           RETVAL = new_color(self, newRV_noinc((SV*)colour), newSVnv(a));
444             OUTPUT:
445             RETVAL
446              
447             SV *
448             hsl(self, h, s, l, ...)
449             SV * self
450             SV * h
451             SV * s
452             SV * l
453             CODE:
454 1 50         double a = clamp(items > 4 ? SvNV(ST(4)) : 1, 1);
455 1           SV * colour = hsl2rgb(SvNV(h), SvNV(s), SvNV(l), a);
456 1           RETVAL = new_color(self, colour, newSVnv(a));
457             OUTPUT:
458             RETVAL
459              
460             SV *
461             hsla(self, h, s, l, ...)
462             SV * self
463             SV * h
464             SV * s
465             SV * l
466             CODE:
467 0 0         double a = clamp(items > 4 ? SvNV(ST(4)) : 1, 1);
468 0           SV * colour = hsl2rgb(SvNV(h), SvNV(s), SvNV(l), a);
469 0           RETVAL = new_color(self, colour, newSVnv(a));
470             OUTPUT:
471             RETVAL
472              
473             SV *
474             toCSS(self, ...)
475             SV * self
476             CODE:
477 17 50         int r = items > 1 ? SvIV(ST(1)) : 0;
478 17 50         int s = items > 2 ? SvIV(ST(1)) : 0;
479 17           double alpha = SvNV(*hv_fetch((HV*)SvRV(self), "alpha", 5, 0));
480 17           alpha = rround(alpha, r);
481 17 100         if (alpha == 1) {
482             char css[8];
483 16           sprintf_colour(self, css, "#%02lx%02lx%02lx");
484 16 50         if (!s) {
485 16           int min = 1;
486 64 100         for (int i = 1; i < 7; i += 2) {
487 48 50         if (css[i] != css[i+1]) {
488 0           min = 0;
489 0           break;
490             }
491             }
492 16 50         if (min) {
493 16           sprintf(css, "#%c%c%c", css[1], css[3], css[5]);
494             }
495             }
496 16           RETVAL = newSVpvn(css, strlen(css));
497             } else {
498 1           char * css = malloc(sizeof(char)*22);
499 1           sprintf_rgba(self, css);
500 1           RETVAL = newSVpvn(css, strlen(css));
501             }
502             OVERLOAD: \"\"
503             OUTPUT:
504             RETVAL
505              
506             SV *
507             toTerm(self)
508             SV * self
509             CODE:
510 5           char * css = malloc(sizeof(char)*12);
511 5           sprintf_colour(self, css, "r%dg%db%d");
512 5           RETVAL = newSVpvn(css, strlen(css));
513             OUTPUT:
514             RETVAL
515              
516             SV *
517             toOnTerm(self)
518             SV * self
519             CODE:
520 5           char * css = malloc(sizeof(char)*15);
521 5           sprintf_colour(self, css, "on_r%dg%db%d");
522 5           RETVAL = newSVpvn(css, strlen(css));
523             OUTPUT:
524             RETVAL
525              
526             SV *
527             toRGB(self, ...)
528             SV * self
529             CODE:
530 9           SV * alpha = *hv_fetch((HV*)SvRV(self), "alpha", 5, 0);
531 9 50         if (numIs(alpha) && SvIV(alpha) != 1) {
    50          
532 0           char * css = malloc(sizeof(char)*22);
533 0           sprintf_rgba(self, css);
534 0           RETVAL = newSVpvn(css, strlen(css));
535             } else {
536 9           char * css = malloc(sizeof(char)*24);
537 9           sprintf_colour(self, css, "rgb(%d,%d,%d)");
538 9           RETVAL = newSVpvn(css, strlen(css));
539             }
540             OUTPUT:
541             RETVAL
542              
543             SV *
544             toRGBA(self, ...)
545             SV * self
546             CODE:
547 44           char * css = malloc(sizeof(char)*22);
548 44           sprintf_rgba(self, css);
549 44           RETVAL = newSVpvn(css, strlen(css));
550             OUTPUT:
551             RETVAL
552              
553             SV *
554             toHEX(self, ...)
555             SV * self
556             CODE:
557             char css[8];
558 11           sprintf_colour(self, css, "#%02lx%02lx%02lx");
559 11 50         if (! SvTRUE(ST(1)) || (SvTRUE(ST(1)) && SvTYPE(ST(1)) != SVt_IV)) {
    50          
    100          
560 6           int min = 1;
561 21 100         for (int i = 1; i < 7; i += 2) {
562 16 100         if (css[i] != css[i+1]) {
563 1           min = 0;
564 1           break;
565             }
566             }
567 6 100         if (min) {
568 5           sprintf(css, "#%c%c%c", css[1], css[3], css[5]);
569             }
570             }
571 11           RETVAL = newSVpvn(css, strlen(css));
572             OUTPUT:
573             RETVAL
574              
575             SV *
576             toHSL(self)
577             SV * self
578             CODE:
579 12           struct HSL colour = asHSL(self);
580             char css[30];
581 12           sprintf(css, "hsl(%d,%s,%s)", colour.h, percent(colour.s), percent(colour.l));
582 12           RETVAL = newSVpvn(css, strlen(css));
583             OUTPUT:
584             RETVAL
585              
586             SV *
587             toHSV(self)
588             SV * self
589             CODE:
590 8           struct HS colour = rgb2hs(self);
591            
592 8 100         colour.s = (colour.max == 0 ) ? colour.max : colour.d / colour.max;
593              
594 8 100         if (colour.max == colour.min) {
595 2           colour.h = 0;
596             } else {
597 12           colour.h = (colour.max == colour.r)
598 4 100         ? (colour.g - colour.b) / colour.d + ( colour.g < colour.b ? 6 : 0 )
599 12 100         : (colour.max == colour.g)
600 1           ? (colour.b - colour.r) / colour.d + 2
601 2 100         : (colour.r - colour.g) / colour.d + 4;
602 6           colour.h = colour.h / 6;
603             }
604             char css[30];
605 8           sprintf(css, "hsv(%.0f,%s,%s)", colour.h * 360, percent(colour.s), percent(colour.max));
606 8           RETVAL = newSVpvn(css, strlen(css));
607             OUTPUT:
608             RETVAL
609              
610             SV *
611             lighten(colour, amt, ...)
612             SV * colour
613             SV * amt
614             CODE:
615 11           SV * class = newSVpv("Colouring::In::XS", 17);
616 11 100         if (SvTYPE(colour) == SVt_PV) {
617 7           colour = new_color(class, colour, newSVnv(1));
618             }
619 11           struct HSL hsl = asHSL(colour);
620 11           double amount = depercent(SvPV_nolen(amt));
621              
622 11 50         if (SvOK(ST(2)) && strcmp(SvPV_nolen(ST(2)), "relative") == 0) {
    100          
623 2           double l = hsl.l || 1.;
624 2           hsl.l = hsl.l + clamp(l * amount, 1);
625             } else {
626 9           hsl.l = hsl.l + clamp(amount, 1);
627             }
628              
629 11           colour = hsl2rgb(hsl.h, hsl.s, hsl.l, hsl.a);
630 11           RETVAL = new_color(class, colour, newSVnv(hsl.a));
631             OUTPUT:
632             RETVAL
633              
634             SV *
635             darken(colour, amt, ...)
636             SV * colour
637             SV * amt
638             CODE:
639 11           SV * class = newSVpv("Colouring::In::XS", 17);
640 11 100         if (SvTYPE(colour) == SVt_PV) {
641 8           colour = new_color(class, colour, newSVnv(1));
642             }
643 11           struct HSL hsl = asHSL(colour);
644 11           double amount = depercent(SvPV_nolen(amt));
645            
646 11 50         if (SvOK(ST(2)) && strcmp(SvPV_nolen(ST(2)), "relative") == 0) {
    100          
647 1           hsl.l = hsl.l - clamp(hsl.l * amount, 1);
648             } else {
649 10           hsl.l = hsl.l - clamp(amount, 1);
650             }
651              
652 11           colour = hsl2rgb(hsl.h, hsl.s, hsl.l, hsl.a);
653 11           RETVAL = new_color(class, colour, newSVnv(hsl.a));
654             OUTPUT:
655             RETVAL
656              
657              
658             SV *
659             fade(colour, amt, ...)
660             SV * colour
661             SV * amt
662             CODE:
663 12           SV * class = newSVpv("Colouring::In::XS", 17);
664 12 50         if (SvTYPE(colour) == SVt_PV) {
665 12           colour = new_color(class, colour, newSVnv(1));
666             }
667 12           struct HSL hsl = asHSL(colour);
668 12           hsl.a = depercent(SvPV_nolen(amt));
669 12           colour = hsl2rgb(hsl.h, hsl.s, hsl.l, hsl.a);
670 12           RETVAL = new_color(class, colour, newSVnv(hsl.a));
671             OUTPUT:
672             RETVAL
673              
674              
675             SV *
676             fadeout(colour, amt, ...)
677             SV * colour
678             SV * amt
679             CODE:
680 14           SV * class = newSVpv("Colouring::In::XS", 17);
681 14 100         if (SvTYPE(colour) == SVt_PV) {
682 11           colour = new_color(class, colour, newSVnv(1));
683             }
684 14           struct HSL hsl = asHSL(colour);
685 14           double amount = depercent(SvPV_nolen(amt));
686 14 100         hsl.a -= clamp((items > 2 && strcmp(SvPV_nolen(ST(2)), "relative") == 0) ? hsl.a * amount : amount, 1);
    100          
687 14           colour = hsl2rgb(hsl.h, hsl.s, hsl.l, hsl.a);
688 14           RETVAL = new_color(class, colour, newSVnv(hsl.a));
689             OUTPUT:
690             RETVAL
691              
692             SV *
693             fadein(colour, amt, ...)
694             SV * colour
695             SV * amt
696             CODE:
697 14           SV * class = newSVpv("Colouring::In::XS", 17);
698 14 100         if (SvTYPE(colour) == SVt_PV) {
699 11           colour = new_color(class, colour, newSVnv(1));
700             }
701 14           struct HSL hsl = asHSL(colour);
702 14           double amount = depercent(SvPV_nolen(amt));
703 14 100         hsl.a += clamp((items > 2 && strcmp(SvPV_nolen(ST(2)), "relative") == 0) ? hsl.a * amount : amount, 1);
    100          
704 14           hsl.a = clamp(hsl.a, 1);
705 14           colour = hsl2rgb(hsl.h, hsl.s, hsl.l, hsl.a);
706 14           RETVAL = new_color(class, colour, newSVnv(hsl.a));
707             OUTPUT:
708             RETVAL
709              
710             SV *
711             mix (colour1, colour2, ...)
712             SV * colour1
713             SV * colour2
714             CODE:
715 1           int weight = 50;
716 1 50         if (SvOK(ST(2)) && SvIV(ST(2)) != 0) {
    50          
717 0           weight = SvIV(ST(2));
718             }
719 1           RETVAL = mix(colour1, colour2, weight);
720             OUTPUT:
721             RETVAL
722              
723             SV *
724             tint (colour, ...)
725             SV * colour
726             CODE:
727 1           int weight = 50;
728 1 50         if (SvOK(ST(2)) && SvIV(ST(2)) != 0) {
    50          
729 0           weight = SvIV(ST(2));
730             }
731 1           SV * white = newSVpv("rgb(255,255,255)", 16);
732 1           RETVAL = mix(white, colour, weight);
733             OUTPUT:
734             RETVAL
735              
736             SV *
737             shade (colour, ...)
738             SV * colour
739             CODE:
740 1           int weight = 50;
741 1 50         if (SvOK(ST(2)) && SvIV(ST(2)) != 0) {
    50          
742 0           weight = SvIV(ST(2));
743             }
744 1           SV * black = newSVpv("rgb(0,0,0)", 10);
745 1           RETVAL = mix(black, colour, weight);
746             OUTPUT:
747             RETVAL
748              
749              
750             SV *
751             saturate (colour, amt, ...)
752             SV * colour
753             SV * amt
754             CODE:
755 1           SV * class = newSVpv("Colouring::In::XS", 17);
756 1 50         if (SvTYPE(colour) == SVt_PV) {
757 1           colour = new_color(class, colour, newSVnv(1));
758             }
759 1           struct HSL hsl = asHSL(colour);
760 1           double amount = depercent(SvPV_nolen(amt));
761 1 50         hsl.s += clamp((items > 2 && strcmp(SvPV_nolen(ST(2)), "relative") == 0) ? hsl.s * amount : amount, 1);
    0          
762 1           colour = hsl2rgb(hsl.h, hsl.s, hsl.l, hsl.a);
763 1           RETVAL = new_color(class, colour, newSVnv(hsl.a));
764             OUTPUT:
765             RETVAL
766              
767             SV *
768             desaturate (colour, amt, ...)
769             SV * colour
770             SV * amt
771             CODE:
772 2           SV * class = newSVpv("Colouring::In::XS", 17);
773 2 50         if (SvTYPE(colour) == SVt_PV) {
774 2           colour = new_color(class, colour, newSVnv(1));
775             }
776 2           struct HSL hsl = asHSL(colour);
777 2           double amount = depercent(SvPV_nolen(amt));
778 2 50         hsl.s -= clamp((items > 2 && strcmp(SvPV_nolen(ST(2)), "relative") == 0) ? hsl.s * amount : amount, 1);
    0          
779 2           colour = hsl2rgb(hsl.h, hsl.s, hsl.l, hsl.a);
780 2           RETVAL = new_color(class, colour, newSVnv(hsl.a));
781             OUTPUT:
782             RETVAL
783              
784              
785             SV *
786             greyscale (colour)
787             SV * colour
788             CODE:
789 1           SV * class = newSVpv("Colouring::In::XS", 17);
790 1 50         if (SvTYPE(colour) == SVt_PV) {
791 1           colour = new_color(class, colour, newSVnv(1));
792             }
793 1           struct HSL hsl = asHSL(colour);
794 1           hsl.s -= 1.;
795 1           colour = hsl2rgb(hsl.h, hsl.s, hsl.l, hsl.a);
796 1           RETVAL = new_color(class, colour, newSVnv(hsl.a));
797             OUTPUT:
798             RETVAL
799              
800            
801             void
802             colour(self)
803             SV * self
804             CODE:
805 10023           int i = 0;
806 10023           AV * colour = colour_array(self);
807 10023           int len = av_len(colour);
808 40092 100         for (i = 0; i <= len; i++) {
809 30069           ST(i) = newSVsv(*av_fetch(colour, i, 0));
810             }
811 10023           XSRETURN(i);
812              
813             SV *
814             get_message(msg)
815             SV * msg
816             CODE:
817 4           char * key = SvPV_nolen(msg);
818 4           RETVAL = *hv_fetch(MESSAGES, key, strlen(key), 0);
819             OUTPUT:
820             RETVAL