File Coverage

blib/lib/Color/Mix.pm
Criterion Covered Total %
statement 136 143 95.1
branch 35 40 87.5
condition 10 11 90.9
subroutine 25 26 96.1
pod 11 11 100.0
total 217 231 93.9


line stmt bran cond sub pod time code
1             package Color::Mix;
2              
3 1     1   62298 use strict;
  1         3  
  1         36  
4 1     1   6 use warnings;
  1         2  
  1         26  
5 1     1   5 use Carp;
  1         13  
  1         1988  
6              
7             our $VERSION = '0.02';
8              
9             sub new {
10 2     2 1 781 my ($class) = shift;
11 2         4 my $self = {};
12 2   66     13 bless $self, ref($class) || $class;
13 2         7 $self->_initialize;
14 2         6 return $self;
15             }
16              
17             ##################################
18             # P U B L I C M E T H O D S
19             ##################################
20              
21             sub analogous {
22 4     4 1 3078 my ($self, $color, $my_slices, $slices) = @_;
23 4   100     16 $my_slices ||= 3;
24 4   100     30 $slices ||= 12;
25 4         10 $color = $self->get_color($color);
26 4         9 my $angle = 360 / $slices;
27 4         11 return $color, map { $self->_rotate($color, $angle*$_) } 1 .. $my_slices;
  13         35  
28             }
29              
30              
31             sub complementary {
32 5     5 1 521 my ($self, $color) = @_;
33 5         12 return $self->_rotate($color, 180);
34             }
35              
36              
37             sub double_complementary {
38 1     1 1 3 my ($self, $primary, $secondary) = @_;
39 1         4 return ($self->complementary($primary), $self->complementary($secondary));
40             }
41              
42              
43             sub trinary {
44 2     2 1 720 my ($self, $primary) = @_;
45 2         5 return ($self->get_color($primary), $self->_rotate($primary, 120), $self->_rotate($primary, 240));
46             }
47              
48              
49             sub lighten {
50 7     7 1 17 my ($self, $color, $by) = @_;
51 7         16 $color = $self->get_color($color);
52 7   100     26 $by||=1;
53 7         14 my $shade = $self->get_shade;
54 7 100       16 return sprintf('%.2x%.2x%.2x', map { ( $_ + $shade * $by > 255) ? 255 : $_ + $shade * $by }
  21         110  
55             $self->_rgb($color));
56             }
57              
58              
59             sub darken {
60 5     5 1 12 my ($self, $color, $by) = @_;
61 5         13 $color = $self->get_color($color);
62 5   100     20 $by||=1;
63 5         10 my $shade = $self->get_shade;
64 5 100       12 return sprintf('%.2x%.2x%.2x', map { ($_ - $shade * $by < 0) ? 0 : $_ - $shade * $by }
  15         417  
65             $self->_rgb($color));
66             }
67              
68              
69             sub get_color {
70 44     44 1 1797 my ($self, $color) = @_;
71 44 100       72 return $color if $self->_is_hex_color($color);
72 10 100       27 return $self->_get_named_color($color) if $self->_is_color_name($color);
73 1         31 carp "Doesn't look like a valid color";
74             }
75              
76              
77             sub get_color_list {
78 0     0 1 0 my ($self) = @_;
79 0         0 return sort keys %{$self->{colors}};
  0         0  
80             }
81              
82              
83             sub set_shade {
84 4     4 1 9 my ($self, $shade) = @_;
85 4         10 $self->{shade_offset} = $shade;
86             }
87              
88              
89             sub get_shade {
90 14     14 1 16 my ($self) = @_;
91 14         38 return $self->{shade_offset};
92             }
93              
94              
95             ##################################
96             # P R I V A T E M E T H O D S
97             ##################################
98              
99             sub _initialize {
100 2     2   3 my ($self) = @_;
101 2         8 $self->_setup_colors;
102 2         10 $self->set_shade(32);
103 2         2 return $self;
104             }
105              
106             sub _rotate {
107 22     22   36 my ($self, $color, $angle) = @_;
108 22         45 my $hsv = $self->_RGB2HSV($color);
109 22         56 $hsv->{hue} = $self->_shift_hue($hsv->{hue}, $angle);
110 22         62 my $rotated = $self->_HSV2RGB($hsv);
111 22         195 return sprintf("%.2x%.2x%.2x", $rotated->{r}, $rotated->{g}, $rotated->{b});
112             }
113              
114              
115             sub _minmax {
116 22     22   41 my($self, @params) = @_;
117 22         31 my $initial = shift @params;
118 22         26 my $max = $initial;
119 22         24 my $min = $initial;
120 22         40 for (@params) {
121 44 100       74 $max = $_ if $_ > $max;
122 44 100       105 $min = $_ if $_ < $min;
123             }
124 22         59 return ($min,$max);
125             }
126              
127              
128             sub _is_hex_color {
129 44     44   58 my ($self, $color) = @_;
130 44 100       164 return 0 unless ($color =~ /^[0-9A-Fa-f]{6}$/);
131 34         124 return 1;
132             }
133              
134              
135             sub _is_color_name {
136 12     12   1350 my ($self, $color) = @_;
137 12 100       29 return 0 unless $self->_get_named_color($color);
138 10         38 return 1;
139             }
140              
141              
142             sub _get_color_names {
143 21     21   27 my ($self) = @_;
144 21         95 return $self->{colors};
145             }
146              
147              
148             sub _RGB2HSV {
149 22     22   31 my ($self, $hex) = @_;
150 22         38 $hex = $self->get_color($hex);
151 22         29 my %hsv;
152 22         46 my ($r,$g,$b) = ($self->_rgb($hex));
153 22         51 my ($min, $max) = $self->_minmax($r,$g,$b);
154 22         36 my $dif = $max - $min;
155 22 50       74 $hsv{saturation} = ($max == 0) ? 0 : (100*$dif / $max);
156 22 50       93 if (!$hsv{saturation}) {
    100          
    100          
    50          
157 0         0 $hsv{hue} = 0;
158             }
159             elsif ($r == $max) {
160 12         25 $hsv{hue} = 60*($g - $b) / $dif;
161             }
162             elsif ($g == $max) {
163 3         8 $hsv{hue} = 120+60*($b - $r) / $dif;
164             }
165             elsif ($b == $max) {
166 7         16 $hsv{hue} = 240+60*($r - $g) / $dif;
167             }
168 22 50       61 $hsv{hue} += 360 if $hsv{hue} < 0;
169 22         68 $hsv{value} = sprintf("%.0f", $max*100 / 255);
170 22         41 $hsv{hue} = sprintf("%.0f", $hsv{hue});
171 22         44 $hsv{saturation} = sprintf("%.0f", $hsv{saturation});
172 22         28 $hsv{r} = $r;
173 22         26 $hsv{g} = $g;
174 22         30 $hsv{b} = $b;
175 22         60 return \%hsv;
176             }
177              
178              
179             sub _HSV2RGB {
180 22     22   25 my ($self, $hsv) = @_;
181 22         24 my ($r,$g,$b,$i,$f,$p,$q,$t,$rgb);
182 22 50       45 if ($hsv->{saturation} eq "0") {
183 0         0 $r = sprintf("%.0f",$hsv->{value} * 2.55);
184 0         0 $g = sprintf("%.0f",$hsv->{value} * 2.55);
185 0         0 $b = sprintf("%.0f",$hsv->{value} * 2.55);
186             }
187             else {
188 22         37 $hsv->{hue} /= 60;
189 22         28 $hsv->{saturation} /= 100;
190 22         36 $hsv->{value} /= 100;
191 22         47 $i = int($hsv->{hue});
192 22         28 $f = $hsv->{hue} - $i;
193 22         41 $p = $hsv->{value}*(1-$hsv->{saturation});
194 22         45 $q = $hsv->{value}*(1-$hsv->{saturation}*$f);
195 22         34 $t = $hsv->{value}*(1-$hsv->{saturation}*(1-$f));
196              
197 22 100       81 if ($i == 0) { $r = $hsv->{value}; $g = $t; $b = $p; }
  3 100       5  
  3 100       14  
  3 100       4  
    100          
198 3         4 elsif ($i == 1) { $r = $q; $g = $hsv->{value}; $b = $p; }
  3         4  
  3         4  
199 3         6 elsif ($i == 2) { $r = $p; $g = $hsv->{value}; $b = $t; }
  3         6  
  3         5  
200 2         4 elsif ($i == 3) { $r = $p; $g = $q; $b = $hsv->{value}; }
  2         2  
  2         3  
201 10         12 elsif ($i == 4) { $r = $t; $g = $p; $b = $hsv->{value}; }
  10         13  
  10         14  
202 1         3 else { $r = $hsv->{value}; $g = $p; $b = $q; }
  1         2  
  1         2  
203              
204 22         44 $r = sprintf('%.0f', $r * 255);
205 22         35 $g = sprintf('%.0f', $g * 255);
206 22         35 $b = sprintf('%.0f', $b * 255);
207             }
208              
209 22         53 $rgb->{r} = $r;
210 22         36 $rgb->{g} = $g;
211 22         29 $rgb->{b} = $b;
212 22         44 return $rgb;
213             }
214            
215              
216             sub _rgb {
217 34     34   42 my ($self, $hex) = @_;
218 34         123 return (hex(substr($hex,0,2)),
219             hex(substr($hex,2,2)),
220             hex(substr($hex,4,2)));
221             }
222              
223              
224             sub _shift_hue {
225 22     22   37 my ($self, $hue, $angle) = @_;
226 22         62 return ($hue + $angle) % 360;
227             }
228              
229              
230             sub _get_named_color {
231 21     21   36 my ($self, $color_name) = @_;
232 21         36 return $self->_get_color_names->{$color_name};
233             }
234              
235              
236             sub _setup_colors {
237 2     2   4 my ($self) = @_;
238 2         726 $self->{colors} = {qw(
239             aliceblue f0f8ff
240             antiquewhite faebd7
241             aqua 00ffff
242             aquamarine 7fffd4
243             azure f0ffff
244             beige f5f5dc
245             bisque ffe4c4
246             black 000000
247             blanchedalmond ffebcd
248             blue 0000ff
249             blueviolet 8a2be2
250             brown a52a2a
251             burlywood deb887
252             cadetblue 5f9ea0
253             chartreuse 7fff00
254             chocolate d2691e
255             coral ff7f50
256             cornflowerblue 6495ed
257             cornsilk fff8dc
258             crimson dc143c
259             cyan 00ffff
260             darkblue 00008b
261             darkcyan 008b8b
262             darkgoldenrod b8860b
263             darkgray a9a9a9
264             darkgreen 006400
265             darkgrey a9a9a9
266             darkkhaki bdb76b
267             darkmagenta 8b008b
268             darkolivegreen 556b2f
269             darkorange ff8c00
270             darkorchid 9932cc
271             darkred 8b0000
272             darksalmon e9967a
273             darkseagreen 8fbc8f
274             darkslateblue 483d8b
275             darkslategray 2f4f4f
276             darkslategrey 2f4f4f
277             darkturquoise 00ced1
278             darkviolet 9400d3
279             deeppink ff1493
280             deepskyblue 00bfff
281             dimgray 696969
282             dimgrey 696969
283             dodgerblue 1e90ff
284             firebrick b22222
285             floralwhite fffaf0
286             forestgreen 228b22
287             fuchsia ff00ff
288             gainsboro dcdcdc
289             ghostwhite f8f8ff
290             gold ffd700
291             goldenrod daa520
292             gray 808080
293             green 008000
294             greenyellow adff2f
295             grey 808080
296             honeydew f0fff0
297             hotpink ff69b4
298             indianred cd5c5c
299             indigo 4b0082
300             ivory fffff0
301             khaki f0e68c
302             lavender e6e6fa
303             lavenderblush fff0f5
304             lawngreen 7cfc00
305             lemonchiffon fffacd
306             lightblue add8e6
307             lightcoral f08080
308             lightcyan e0ffff
309             lightgoldenrodyellow fafad2
310             lightgray d3d3d3
311             lightgreen 90ee90
312             lightgrey d3d3d3
313             lightpink ffb6c1
314             lightsalmon ffa07a
315             lightseagreen 20b2aa
316             lightskyblue 87cefa
317             lightslategray 778899
318             lightslategrey 778899
319             lightsteelblue b0c4de
320             lightyellow ffffe0
321             lime 00ff00
322             limegreen 32cd32
323             linen faf0e6
324             magenta ff00ff
325             maroon 800000
326             mediumaquamarine 66cdaa
327             mediumblue 0000cd
328             mediumorchid ba55d3
329             mediumpurple 9370db
330             mediumseagreen 3cb371
331             mediumslateblue 7b68ee
332             mediumspringgreen 00fa9a
333             mediumturquoise 48d1cc
334             mediumvioletred c71585
335             midnightblue 191970
336             mintcream f5fffa
337             mistyrose ffe4e1
338             moccasin ffe4b5
339             navajowhite ffdead
340             navy 000080
341             oldlace fdf5e6
342             olive 808000
343             olivedrab 6b8e23
344             orange ffa500
345             orangered ff4500
346             orchid da70d6
347             palegoldenrod eee8aa
348             palegreen 98fb98
349             paleturquoise afeeee
350             palevioletred db7093
351             papayawhip ffefd5
352             peachpuff ffdab9
353             peru cd853f
354             pink ffc0cb
355             plum dda0dd
356             powderblue b0e0e6
357             purple 800080
358             red ff0000
359             rosybrown bc8f8f
360             royalblue 4169e1
361             saddlebrown 8b4513
362             salmon fa8072
363             sandybrown f4a460
364             seagreen 2e8b57
365             seashell fff5ee
366             sienna a0522d
367             silver c0c0c0
368             skyblue 87ceeb
369             slateblue 6a5acd
370             slategray 708090
371             slategrey 708090
372             snow fffafa
373             springgreen 00ff7f
374             steelblue 4682b4
375             tan d2b48c
376             teal 008080
377             thistle d8bfd8
378             tomato ff6347
379             turquoise 40e0d0
380             violet ee82ee
381             wheat f5deb3
382             white ffffff
383             whitesmoke f5f5f5
384             yellow ffff00
385             yellowgreen 9acd32
386             )};
387             }
388              
389              
390             1;
391              
392             __END__