File Coverage

lib/Graphics/Toolkit/Color/Values.pm
Criterion Covered Total %
statement 101 101 100.0
branch 33 42 78.5
condition 4 12 33.3
subroutine 15 15 100.0
pod 0 10 0.0
total 153 180 85.0


line stmt bran cond sub pod time code
1              
2             # read only store a single color: name + values in default and original space
3              
4             package Graphics::Toolkit::Color::Values;
5 9     9   632880 use v5.12;
  9         37  
6 9     9   52 use warnings;
  9         17  
  9         664  
7 9     9   5065 use Graphics::Toolkit::Color::Name;
  9         47  
  9         896  
8 9     9   111 use Graphics::Toolkit::Color::Space::Hub;
  9         19  
  9         15149  
9              
10             my $RGB = Graphics::Toolkit::Color::Space::Hub::default_space();
11              
12             #### constructor #######################################################
13             sub new_from_any_input { # values => %space_name => tuple , ~origin_space, ~color_name
14 137     137 0 620368 my ($pkg, $color_def) = @_;
15 137 50       356 return "Can not create color value object without color definition!" unless defined $color_def;
16 137 100       382 if (not ref $color_def) { # try to resolve color name
17 67         306 my $rgb = Graphics::Toolkit::Color::Name::get_values( $color_def );
18 67 100       172 if (ref $rgb){
19 41         166 $rgb = $RGB->clamp( $RGB->normalize( $rgb ), 'normal' );
20 41         305 return bless { name => $color_def, rgb => $rgb, source_values => '', source_space_name => ''};
21             }
22             }
23 96         316 my ($values, $space_name) = Graphics::Toolkit::Color::Space::Hub::deformat( $color_def );
24 96 100       467 return "could not recognize color value format or color name: $color_def" unless ref $values;
25 54         176 new_from_tuple( '', $values, $space_name);
26             }
27             sub new_from_tuple { #
28 476     476 0 243727 my ($pkg, $values, $space_name, $range_def) = @_;
29 476         1204 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $space_name );
30 476 50       1128 return $color_space unless ref $color_space;
31 476 100       4306 return "Need ARRAY of ".$color_space->axis_count." ".$color_space->name." values as first argument!"
32             unless $color_space->is_value_tuple( $values );
33 475         1325 $values = $color_space->clamp( $values, $range_def);
34 475         1304 $values = $color_space->normalize( $values, $range_def );
35 475         1184 $values = $color_space->clamp( $values, 'normal');
36 475         2630 _new_from_normal_tuple($values, $color_space);
37             }
38             sub _new_from_normal_tuple { #
39 475     475   912 my ($values, $color_space) = @_;
40 475         820 my $source_values = '';
41 475         751 my $source_space_name = '';
42 475 100       1198 if ($color_space->name ne $RGB->name){
43 123         216 $source_values = $values;
44 123         263 $source_space_name = $color_space->name;
45 123         329 $values = Graphics::Toolkit::Color::Space::Hub::deconvert( $color_space->name, $values, 'normal' );
46             }
47 475         1409 $values = $RGB->clamp( $values, 'normal' );
48 475         1397 my $name = Graphics::Toolkit::Color::Name::from_values( $RGB->round( $RGB->denormalize( $values ) ) );
49 475         4973 bless { rgb => $values, source_values => $source_values, source_space_name => $source_space_name, name => $name };
50             }
51              
52             #### getter ############################################################
53             sub normalized { # normalized (0..1) value tuple in any color space
54 369     369 0 18104 my ($self, $space_name) = @_;
55             Graphics::Toolkit::Color::Space::Hub::convert(
56 369         1524 $self->{'rgb'}, $space_name, 'normal', $self->{'source_space_name'}, $self->{'source_values'},
57             );
58             }
59             sub shaped { # in any color space, range and precision
60 323     323 0 90808 my ($self, $space_name, $range_def, $precision_def) = @_;
61 323         775 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $space_name );
62 323 50       782 return $color_space unless ref $color_space;
63 323         789 my $values = $self->normalized( $color_space->name );
64 323 50       850 return $values if not ref $values;
65 323         809 $values = $color_space->denormalize( $values, $range_def );
66 323         876 $values = $color_space->clamp( $values, $range_def );
67 323         827 $values = $color_space->round( $values, $precision_def );
68 323         1860 return $values;
69             }
70             sub formatted { # in shape values in any format # _ -- ~space, @~|~format, @~|~range, @~|~suffix
71 77     77 0 55879 my ($self, $space_name, $format_name, $suffix_def, $range_def, $precision_def) = @_;
72 77         255 my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $space_name );
73 77 50       174 return $color_space unless ref $color_space;
74 77         299 my $values = $self->shaped( $color_space->name, $range_def, $precision_def );
75 77 50       239 return $values unless ref $values;
76 77         234 return $color_space->format( $values, $format_name, $suffix_def );
77             }
78 67     67 0 56169 sub name { $_[0]->{'name'} }
79              
80             #### single color calculator ###########################################
81             sub set { # .values, %newval -- ~space_name --> _
82 13     13 0 4658 my ($self, $partial_hash, $preselected_space_name) = @_;
83 13         41 my ($new_values, $space_name) = Graphics::Toolkit::Color::Space::Hub::deformat_partial_hash(
84             $partial_hash, $preselected_space_name );
85 13 100       26 unless (ref $new_values){
86 4         16 my $help_start = 'axis names: '.join(', ', keys %$partial_hash).' do not correlate to ';
87 4 100       40 return (defined $preselected_space_name) ? $help_start.'the selected color space: '.$preselected_space_name.'!'
88             : 'any supported color space!';
89             }
90 9         35 my $values = $self->shaped( $space_name );
91 9         41 my $color_space = Graphics::Toolkit::Color::Space::Hub::get_space( $space_name );
92 9         21 for my $pos ($color_space->basis->axis_iterator) {
93 27 100       54 $values->[$pos] = $new_values->[$pos] if defined $new_values->[$pos];
94             }
95 9         20 $self->new_from_tuple( $values, $color_space->name );
96             }
97              
98             sub add { # .values, %newval -- ~space_name --> _
99 13     13 0 9221 my ($self, $partial_hash, $preselected_space_name) = @_;
100 13         38 my ($new_values, $space_name) = Graphics::Toolkit::Color::Space::Hub::deformat_partial_hash(
101             $partial_hash, $preselected_space_name );
102 13 100       29 unless (ref $new_values){
103 5         19 my $help_start = 'axis names: '.join(', ', keys %$partial_hash).' do not correlate to ';
104 5 100       32 return (defined $preselected_space_name) ? $help_start.'the selected color space: '.$preselected_space_name.'!'
105             : 'any supported color space!';
106             }
107 8         23 my $values = $self->shaped( $space_name );
108 8         23 my $color_space = Graphics::Toolkit::Color::Space::Hub::get_space( $space_name );
109 8         21 for my $pos ($color_space->basis->axis_iterator) {
110 24 100       47 $values->[$pos] += $new_values->[$pos] if defined $new_values->[$pos];
111             }
112 8         36 $self->new_from_tuple( $values, $color_space->name );
113             }
114              
115             sub mix { # @%(+percent, _color) -- ~space_name --> _
116 74     74 0 4912 my ($self, $recipe, $color_space ) = @_;
117 74 50       191 return if ref $recipe ne 'ARRAY';
118 74         96 my $percentage_sum = 0;
119 74         111 for my $ingredient (@{$recipe}){
  74         161  
120 80 50 33     354 return if ref $ingredient ne 'HASH' or not exists $ingredient->{'percent'};
121             return if ref $ingredient ne 'HASH' or not exists $ingredient->{'percent'}
122 80 50 33     545 or not exists $ingredient->{'color'} or ref $ingredient->{'color'} ne __PACKAGE__;
      33        
      33        
123 80         162 $percentage_sum += $ingredient->{'percent'};
124             }
125 74         235 my $result_values = [(0) x $color_space->axis_count];
126 74 100       163 if ($percentage_sum < 100){
127 68         144 my $values = $self->shaped( $color_space->name );
128 68         156 my $mix_amount = (100 - $percentage_sum) / 100;
129 68         387 $result_values->[$_] += $values->[$_] * $mix_amount for 0 .. $#$values;
130             } else {
131 6         15 $percentage_sum /= 100;
132 6         9 $_->{'percent'} /= $percentage_sum for @{$recipe}; # sum of percentages has to be 100
  6         21  
133             }
134 74         134 for my $ingredient (@$recipe){
135 80         203 my $values = $ingredient->{'color'}->shaped( $color_space->name );
136 80         505 $result_values->[$_] += $values->[$_] * $ingredient->{'percent'} / 100 for 0 .. $#$values;
137             }
138 74         181 $self->new_from_tuple( $result_values, $color_space->name );
139             }
140              
141             sub invert {
142 18     18 0 3777 my ($self, $color_space ) = @_;
143 18         67 my $values = $self->normalized( $color_space->name );
144 18         43 $self->new_from_tuple( [ map {1 - $_} @$values ], $color_space->name, 'normal' );
  54         133  
145             }
146              
147             1;