File Coverage

lib/Template/Colour/RGB.pm
Criterion Covered Total %
statement 111 143 77.6
branch 55 112 49.1
condition 2 9 22.2
subroutine 14 16 87.5
pod 1 15 6.6
total 183 295 62.0


line stmt bran cond sub pod time code
1             package Template::Colour::RGB;
2              
3             use Template::Colour::Class
4 3         31 version => 2.10,
5             debug => 0,
6             base => 'Template::Colour',
7             constants => 'ARRAY HASH SCHEME :RGB',
8             utils => 'is_object',
9             as_text => 'HTML',
10             is_true => 1,
11 3     3   17 throws => 'Colour.RGB';
  3         6  
12              
13              
14             sub new {
15 210     210 1 6935 my ($proto, @args) = @_;
16 210         195 my ($class, $self);
17              
18 210 100       441 if ($class = ref $proto) {
19 128         356 $self = bless [@$proto], $class;
20             }
21             else {
22 82         282 $self = bless [0, 0, 0], $proto;
23             }
24 210 100       675 $self->rgb(@args) if @args;
25 208         1176 return $self;
26             }
27              
28             sub copy {
29 128     128 0 132 my $self = shift;
30 128 50 33     318 my $args = @_ && ref $_[0] eq HASH ? shift : { @_ };
31 128 50       332 $args->{ red } = $self->[RED] unless defined $args->{ red };
32 128 50       280 $args->{ green } = $self->[GREEN] unless defined $args->{ green };
33 128 50       236 $args->{ blue } = $self->[BLUE] unless defined $args->{ blue };
34 128         198 $self->new($args);
35             }
36              
37             sub rgb {
38 226     226 0 365 my $self = shift;
39 226         207 my $col;
40            
41 226 100       439 if (@_ == 1) {
    100          
    50          
    100          
42             # single argument is a list or hash ref, or RGB value
43 171         188 $col = shift;
44             }
45             elsif (@_ == 3) {
46             # three arguments provide red, green, blue components
47 29         75 $col = [ @_ ];
48             }
49             elsif (@_ == 6) {
50             # list of six items is red => $r, green => $g, blue => $b
51 0         0 $col = { @_ };
52             }
53             elsif (@_) {
54             # any other number of arguments is an error
55 2         38 return $self->error_msg( bad_param => rgb => join(', ', @_) );
56             }
57             else {
58             # return $self when called with no arguments
59 24         62 return $self;
60             }
61            
62             # at this point $col is a reference to a list or hash, or a rgb value
63              
64 200 100       742 if (UNIVERSAL::isa($col, HASH)) {
    100          
    50          
65             # convert hash ref to list
66 387 50       955 $col = [ map {
67 129         133 defined $col->{ $_ }
68             ? $col->{ $_ }
69             : return $self->error_msg( no_param => rgb => $_ );
70             } qw( red green blue ) ];
71             }
72             elsif (UNIVERSAL::isa($col, ARRAY)) {
73             # $col list is ok as it is
74             }
75             elsif (ref $col) {
76             # anything other kind of reference is Not Allowed
77 0         0 return $self->error_msg( bad_param => rgb => $col );
78             }
79             else {
80 40         90 $self->hex($col);
81 40         60 return $self;
82             }
83              
84             # ensure all rgb component values are in range 0-255
85 160         259 for (@$col) {
86 480 50       705 $_ = 0 if $_ < 0;
87 480 50       873 $_ = 255 if $_ > 255;
88             }
89              
90             # update self with new colour, also deletes any cached HSV
91 160         641 @$self = @$col;
92              
93 160         269 return $self;
94             }
95              
96             sub hex {
97 90     90 0 399 my $self = shift;
98              
99 90 100       188 if (@_) {
100 40         45 my $hex = shift;
101 40 50       100 $hex = '' unless defined $hex;
102 40 100       284 if ($hex =~ / ^
    50          
103             \#? # short form of hex triplet: #abc
104             ([0-9a-f]) # red
105             ([0-9a-f]) # green
106             ([0-9a-f]) # blue
107             $
108             /ix) {
109 4         24 @$self = map { hex } ("$1$1", "$2$2", "$3$3");
  12         34  
110             }
111             elsif ($hex =~ / ^
112             \#? # long form of hex triple: #aabbcc
113             ([0-9a-f]{2}) # red
114             ([0-9a-f]{2}) # green
115             ([0-9a-f]{2}) # blue
116             $
117             /ix) {
118 36         59 @$self = map { hex } ($1, $2, $3);
  108         540  
119             }
120             else {
121 0         0 return $self->error_msg( bad_param => hex => $hex );
122             }
123             }
124 90         451 return sprintf("%02x%02x%02x", @$self);
125             }
126              
127             sub HEX {
128 0     0 0 0 my $self = shift;
129 0         0 return uc $self->hex(@_);
130             }
131              
132             sub html {
133 5     5 0 27 my $self = shift;
134 5         12 return '#' . $self->hex();
135             }
136              
137             sub HTML {
138 29     29 0 919 my $self = shift;
139 29         63 return '#' . uc $self->hex();
140             }
141              
142             sub red {
143 16     16 0 899 my $self = shift;
144 16 100       44 if (@_) {
145 2         5 $self->[RED] = shift;
146 2 50       8 $self->[RED] = 0 if $self->[RED] < 0;
147 2 50       8 $self->[RED] = 255 if $self->[RED] > 255;
148 2         7 delete $self->[SCHEME];
149             }
150 16         71 $self->[RED];
151             }
152              
153             sub green {
154 12     12 0 116 my $self = shift;
155 12 50       57 if (@_) {
156 0         0 $self->[GREEN] = shift;
157 0 0       0 $self->[GREEN] = 0 if $self->[GREEN] < 0;
158 0 0       0 $self->[GREEN] = 255 if $self->[GREEN] > 255;
159 0         0 delete $self->[SCHEME];
160             }
161 12         47 $self->[GREEN];
162             }
163              
164             sub blue {
165 12     12 0 100 my $self = shift;
166 12 50       28 if (@_) {
167 0         0 $self->[BLUE] = shift;
168 0 0       0 $self->[BLUE] = 0 if $self->[BLUE] < 0;
169 0 0       0 $self->[BLUE] = 255 if $self->[BLUE] > 255;
170 0         0 delete $self->[SCHEME];
171             }
172 12         42 $self->[BLUE];
173             }
174              
175             sub grey {
176 1     1 0 19 my $self = shift;
177              
178 1 50       5 if (@_) {
179 0         0 delete $self->[SCHEME];
180 0         0 return ($self->[RED] = $self->[GREEN] = $self->[BLUE] = shift);
181             }
182             else {
183 1         8 return int( $self->[RED] * 0.222
184             + $self->[GREEN]* 0.707
185             + $self->[BLUE] * 0.071 );
186             }
187             }
188              
189             sub update {
190 0     0 0 0 my $self = shift;
191 0 0 0     0 my $args = @_ && ref $_[0] eq HASH ? shift : { @_ };
192 0         0 my $value;
193 0 0       0 if (defined ($value = $args->{ red })) {
194 0         0 $self->[RED] = $value;
195 0 0       0 $self->[RED] = 0 if $self->[RED] < 0;
196 0 0       0 $self->[RED] = 255 if $self->[RED] > 255;
197             }
198 0 0       0 if (defined ($value = $args->{ green })) {
199 0         0 $self->[GREEN] = $value;
200 0 0       0 $self->[GREEN] = 0 if $self->[GREEN] < 0;
201 0 0       0 $self->[GREEN] = 255 if $self->[GREEN] > 255;
202             }
203 0 0       0 if (defined ($value = $args->{ blue })) {
204 0         0 $self->[BLUE] = $value;
205 0 0       0 $self->[BLUE] = 0 if $self->[BLUE] < 0;
206 0 0       0 $self->[BLUE] = 255 if $self->[BLUE] > 255;
207             }
208 0         0 delete $self->[SCHEME];
209 0         0 return $self;
210             }
211              
212             sub adjust {
213 106     106 0 112 my $self = shift;
214 106 50 33     415 my $args = @_ && ref $_[0] eq HASH ? shift : { @_ };
215 106         83 my $delta;
216 106 50       202 if (defined ($delta = $args->{ red })) {
217 106         120 $self->[RED] += $delta;
218 106 50       183 $self->[RED] = 0 if $self->[RED] < 0;
219 106 50       180 $self->[RED] = 255 if $self->[RED] > 255;
220             }
221 106 50       188 if (defined ($delta = $args->{ green })) {
222 106         110 $self->[GREEN] += $delta;
223 106 50       176 $self->[GREEN] = 0 if $self->[GREEN] < 0;
224 106 50       162 $self->[GREEN] = 255 if $self->[GREEN] > 255;
225             }
226 106 50       185 if (defined ($delta = $args->{ blue })) {
227 106         108 $self->[BLUE] += $delta;
228 106 50       161 $self->[BLUE] = 0 if $self->[BLUE] < 0;
229 106 50       175 $self->[BLUE] = 255 if $self->[BLUE] > 255;
230             }
231 106         92 delete $self->[SCHEME];
232 106         374 return $self;
233             }
234              
235             sub range {
236 22     22 0 26 my $self = shift;
237 22         22 my $steps = shift;
238 22         62 my $target = $self->SUPER::new(@_)->rgb();
239 22         51 my $dred = ($target->[RED] - $self->[RED]) / $steps;
240 22         33 my $dgreen = ($target->[GREEN] - $self->[GREEN]) / $steps;
241 22         30 my $dblue = ($target->[BLUE] - $self->[BLUE]) / $steps;
242 22         16 my ($n, @range);
243            
244 22         50 for ($n = 0; $n <= $steps; $n++) {
245 106         177 push(@range, $self->copy->adjust({
246             red => $dred * $n,
247             green => $dgreen * $n,
248             blue => $dblue * $n,
249             }));
250             }
251 22 50       104 return wantarray ? @range : \@range;
252             }
253              
254             #------------------------------------------------------------------------
255             # hsv()
256             # hsv($h, $s, $v)
257             #
258             # Convert RGB to HSV, with optional $h, $s and/or $v arguments.
259             #------------------------------------------------------------------------
260              
261             sub hsv {
262 33     33 0 262 my ($self, @args) = @_;
263 33         30 my $hsv;
264              
265             # generate HSV values from current RGB if no arguments provided
266 33 50       69 unless (@args) {
267 33         51 my ($r, $g, $b) = @$self;
268 33         37 my ($h, $s, $v);
269 33         117 my $min = $self->min($r, $g, $b);
270 33         103 my $max = $self->max($r, $g, $b);
271 33         45 my $delta = $max - $min;
272 33         37 $v = $max;
273              
274 33 100       59 if($delta){
275 30         44 $s = $delta / $max;
276 30 100       68 if ($r == $max) {
    100          
277 24         36 $h = 60 * ($g - $b) / $delta;
278             }
279             elsif ($g == $max) {
280 2         7 $h = 120 + (60 * ($b - $r) / $delta);
281             }
282             else { # if $b == $max
283 4         14 $h = 240 + (60 * ($r - $g) / $delta);
284             }
285            
286 30 50       60 $h += 360 if $h < 0; # hue is in the range 0-360
287 30         40 $h = int( $h + 0.5 ); # smooth out rounding errors
288 30         37 $s = int($s * 255); # expand saturation to 0-255
289             }
290             else {
291 3         6 $h = $s = 0;
292             }
293 33         77 @args = ($h, $s, $v);
294             }
295              
296 33         100 $self->HSV(@args);
297             }
298              
299              
300             1;
301              
302             =head1 NAME
303              
304             Template::Colour::RGB - module for RGB colour manipulation
305              
306             =head1 SYNOPSIS
307              
308             See L
309              
310             =head1 DESCRIPTION
311              
312             See L until I get around to updating
313             the docs to show examples of use from Perl.
314              
315             =head1 AUTHOR
316              
317             Andy Wardley Eabw@cpan.orgE, L
318              
319             =head1 COPYRIGHT
320              
321             Copyright (C) 2006-2012 Andy Wardley. All Rights Reserved.
322              
323             This module is free software; you can redistribute it and/or
324             modify it under the same terms as Perl itself.
325              
326             =head1 SEE ALSO
327              
328             L, L, L
329              
330             =cut
331              
332             # Local Variables:
333             # mode: perl
334             # perl-indent-level: 4
335             # indent-tabs-mode: nil
336             # End:
337             #
338             # vim: expandtab shiftwidth=4:
339