File Coverage

lib/Graphics/Toolkit/Color/Name.pm
Criterion Covered Total %
statement 95 100 95.0
branch 72 88 81.8
condition 11 18 61.1
subroutine 17 17 100.0
pod 9 9 100.0
total 204 232 87.9


line stmt bran cond sub pod time code
1 5     5   758 use v5.12;
  5         24  
2              
3             # named colors from X11, HTML (SVG) standard and Pantone report
4              
5             package Graphics::Toolkit::Color::Name;
6 5     5   2372 use Graphics::Toolkit::Color::Values;
  5         12  
  5         155  
7 5     5   30 use Carp;
  5         9  
  5         8767  
8              
9             my $RGB = Graphics::Toolkit::Color::Space::Hub::get_space('RGB');
10             my $HSL = Graphics::Toolkit::Color::Space::Hub::get_space('HSL');
11             my $constants = require Graphics::Toolkit::Color::Name::Constant;
12             our (@name_from_rgb, @name_from_hsl); # search caches
13             _add_color_to_reverse_search( $_, @{$constants->{$_}} ) for all();
14              
15 6     6 1 3600 sub all { sort keys %$constants }
16 45     45 1 1032 sub taken { exists $constants->{ _clean($_[0]) } }
17              
18             sub rgb_from_name {
19 18     18 1 9116 my $name = _clean(shift);
20 18 100       36 @{$constants->{$name}}[0..2] if taken( $name );
  17         106  
21             }
22              
23             sub hsl_from_name {
24 20     20 1 41 my $name = _clean(shift);
25 20 50       36 @{$constants->{$name}}[3..5] if taken( $name );
  20         101  
26             }
27              
28             sub name_from_rgb {
29 123     123 1 235 my (@rgb) = @_;
30 123 100       267 @rgb = @{$rgb[0]} if (ref $rgb[0] eq 'ARRAY');
  1         3  
31 123 50       299 $RGB->check( [@rgb] ) and return; # return if sub did carp
32 123         291 my @names = _names_from_rgb( @rgb );
33 123 50       950 wantarray ? @names : $names[0];
34             }
35              
36             sub name_from_hsl {
37 2     2 1 5 my (@hsl) = @_;
38 2 50       7 @hsl = @{$hsl[0]} if (ref $hsl[0] eq 'ARRAY');
  0         0  
39 2 50       8 $HSL->check( [ @hsl ] ) and return;
40 2         9 my @names = _names_from_hsl( @hsl );
41 2 50       52 wantarray ? @names : $names[0];
42             }
43              
44             sub names_in_hsl_range { # @center, (@d | $d) --> @names
45 17     17 1 14168 my $help = 'need two arguments: 1. array with h s l values '.
46             '2. radius (real number) or array with tolerances in h s l direction';
47 17 100       53 return carp $help if @_ != 2;
48 15         41 my ($hsl_center, $radius) = @_;
49 15 100       49 $HSL->check( $hsl_center ) and return;
50 8 100       33 my $hsl_delta = (ref $radius eq 'ARRAY') ? $radius : [$radius, $radius, $radius];
51 8 100       17 $HSL->check( $hsl_delta ) and return;
52              
53 7 50       15 $hsl_delta->[0] = 180 if $hsl_delta->[0] > 180; # enough to search complete HSL space (prevent double results)
54 7         12 my (@min, @max, @names, $minhrange, $maxhrange);
55 7         26 $min[$_] = $hsl_center->[$_] - $hsl_delta->[$_] for 0..2;
56 7         19 $max[$_] = $hsl_center->[$_] + $hsl_delta->[$_] for 0..2;
57 7 100       14 $min[1] = 0 if $min[1] < 0;
58 7 50       15 $min[2] = 0 if $min[2] < 0;
59 7 100       15 $max[1] = 100 if $max[1] > 100;
60 7 100       10 $max[2] = 100 if $max[2] > 100;
61 7 100       41 my @hrange = ($min[0] < 0) ? ( 0 .. $max[0] , $min[0]+360 .. 359)
    100          
62             : ($max[0] > 360) ? ( 0 .. $max[0]-360, $min[0] .. 359)
63             : ($min[0] .. $max[0]);
64 7         14 for my $h (@hrange){
65 657 100       1025 next unless defined $name_from_hsl[ $h ];
66 323         409 for my $s ($min[1] .. $max[1]){
67 2088 100       3398 next unless defined $name_from_hsl[ $h ][ $s ];
68 166         202 for my $l ($min[2] .. $max[2]){
69 2001         2277 my $name = $name_from_hsl[ $h ][ $s ][ $l ];
70 2001 100       3143 next unless defined $name;
71 87 100       161 push @names, (ref $name ? $name->[0] : $name);
72             }
73             }
74             }
75 7 100       19 @names = grep {Graphics::Toolkit::Color::Values->new(['HSL',@$hsl_center])->distance(
  18         69  
76             Graphics::Toolkit::Color::Values->new(['HSL',hsl_from_name($_)]) ) <= $radius} @names if not ref $radius;
77 7         150 @names;
78             }
79              
80             sub add_rgb {
81 6     6 1 4383 my ($name, @rgb) = @_;
82 6 50       20 @rgb = @{$rgb[0]} if (ref $rgb[0] eq 'ARRAY');
  0         0  
83 6 100 66     44 return carp "missing first argument: color name" unless defined $name and $name;
84 5 100       20 $RGB->check( [@rgb] ) and return;
85 2         17 my @hsl = $HSL->deconvert( [$RGB->normalize( \@rgb )], 'RGB');
86 2         10 _add_color( $name, @rgb, $HSL->denormalize(\@hsl) );
87             }
88              
89             sub add_hsl {
90 2     2 1 7 my ($name, @hsl) = @_;
91 2 50       6 @hsl = @{$hsl[0]} if (ref $hsl[0] eq 'ARRAY');
  0         0  
92 2 50 33     10 return carp "missing first argument: color name" unless defined $name and $name;
93 2 50       7 $HSL->check( \@hsl ) and return;
94 2         6 my @rgb = $HSL->convert( [$HSL->normalize( \@hsl )], 'RGB');
95 2         7 _add_color( $name, $RGB->denormalize( \@rgb ), @hsl );
96             }
97              
98             sub _add_color {
99 4     4   10 my ($name, @rgb, @hsl) = @_;
100 4         7 $name = _clean( $name );
101 4 100       10 return carp "there is already a color named '$name' in store of ".__PACKAGE__ if taken( $name );
102 3         8 _add_color_to_reverse_search( $name, @rgb, @hsl);
103 3         9 my $ret = $constants->{$name} = [@rgb, @hsl]; # add to foreward search
104 3 50       24 (ref $ret) ? [@$ret] : ''; # make returned ref not transparent
105             }
106              
107             sub _clean {
108 88     88   131 my $name = shift;
109 88         150 $name =~ tr/_//d;
110 88         298 lc $name;
111             }
112              
113             sub _names_from_rgb { # each of AoAoA cells (if exists) contains name or array with names (shortes first)
114 123 100 100 123   771 return '' unless exists $name_from_rgb[ $_[0] ]
      100        
115             and exists $name_from_rgb[ $_[0] ][ $_[1] ] and exists $name_from_rgb[ $_[0] ][ $_[1] ][ $_[2] ];
116 58         129 my $cell = $name_from_rgb[ $_[0] ][ $_[1] ][ $_[2] ];
117 58 100       163 ref $cell ? @$cell : $cell;
118             }
119              
120             sub _names_from_hsl {
121 2 50 33 2   13 return '' unless exists $name_from_hsl[ $_[0] ]
      33        
122             and exists $name_from_hsl[ $_[0] ][ $_[1] ] and exists $name_from_hsl[ $_[0] ][ $_[1] ][ $_[2] ];
123 2         5 my $cell = $name_from_hsl[ $_[0] ][ $_[1] ][ $_[2] ];
124 2 100       7 ref $cell ? @$cell : $cell;
125             }
126              
127             sub _add_color_to_reverse_search { # my ($name, @rgb, @hsl) = @_;
128 3583     3583   4023 my $name = $_[0];
129 3583         10450 my $cell = $name_from_rgb[ $_[1] ][ $_[2] ][ $_[3] ];
130 3583 100       5573 if (defined $cell) {
131 286 100       431 if (ref $cell) {
132 21 50       59 if (length $name < length $cell->[0] ) { unshift @$cell, $name }
  0         0  
133 21         50 else { push @$cell, $name }
134             } else {
135 265 100       667 $name_from_rgb[ $_[1] ][ $_[2] ][ $_[3] ] =
136             (length $name < length $cell) ? [ $name, $cell ]
137             : [ $cell, $name ] ;
138             }
139 3297         12931 } else { $name_from_rgb[ $_[1] ][ $_[2] ][ $_[3] ] = $name }
140              
141 3583         9135 $cell = $name_from_hsl[ $_[4] ][ $_[5] ][ $_[6] ];
142 3583 100       4914 if (defined $cell) {
143 331 100       457 if (ref $cell) {
144 21 50       39 if (length $name < length $cell->[0] ) { unshift @$cell, $name }
  0         0  
145 21         44 else { push @$cell, $name }
146             } else {
147 310 100       784 $name_from_hsl[ $_[4] ][ $_[5] ][ $_[6] ] =
148             (length $name < length $cell) ? [ $name, $cell ]
149             : [ $cell, $name ] ;
150             }
151 3252         8964 } else { $name_from_hsl[ $_[4] ][ $_[5] ][ $_[6] ] = $name }
152             }
153              
154             1;
155              
156             __END__