| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
# public user level API: docs, help and arg cleaning |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Graphics::Toolkit::Color; |
|
5
|
|
|
|
|
|
|
our $VERSION = '1.972'; |
|
6
|
|
|
|
|
|
|
|
|
7
|
4
|
|
|
4
|
|
601539
|
use v5.12; |
|
|
4
|
|
|
|
|
15
|
|
|
8
|
4
|
|
|
4
|
|
24
|
use warnings; |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
295
|
|
|
9
|
4
|
|
|
4
|
|
22
|
use Exporter 'import'; |
|
|
4
|
|
|
|
|
29
|
|
|
|
4
|
|
|
|
|
168
|
|
|
10
|
4
|
|
|
4
|
|
1003
|
use Graphics::Toolkit::Color::Space::Util qw/is_nr/; |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
287
|
|
|
11
|
4
|
|
|
4
|
|
2141
|
use Graphics::Toolkit::Color::SetCalculator; |
|
|
4
|
|
|
|
|
14
|
|
|
|
4
|
|
|
|
|
18711
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
my $default_space_name = Graphics::Toolkit::Color::Space::Hub::default_space_name(); |
|
14
|
|
|
|
|
|
|
our @EXPORT_OK = qw/color/; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
## constructor ######################################################### |
|
17
|
|
|
|
|
|
|
|
|
18
|
23
|
|
|
23
|
1
|
928748
|
sub color { Graphics::Toolkit::Color->new ( @_ ) } |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub new { |
|
21
|
86
|
|
|
86
|
1
|
2364
|
my ($pkg, @args) = @_; |
|
22
|
86
|
|
|
|
|
273
|
my $help = <
|
|
23
|
|
|
|
|
|
|
constructor new of Graphics::Toolkit::Color object needs either: |
|
24
|
|
|
|
|
|
|
1. a color name: new('red') or new('SVG:red') |
|
25
|
|
|
|
|
|
|
3. RGB hex string new('#FF0000') or new('#f00') |
|
26
|
|
|
|
|
|
|
4. $default_space_name array or ARRAY ref: new( 255, 0, 0 ) or new( [255, 0, 0] ) |
|
27
|
|
|
|
|
|
|
5. named array or ARRAY ref: new( 'HSL', 255, 0, 0 ) or new( ['HSL', 255, 0, 0 ]) |
|
28
|
|
|
|
|
|
|
6. named string: new( 'HSL: 0, 100, 50' ) or new( 'ncol(r0, 0%, 0%)' ) |
|
29
|
|
|
|
|
|
|
7. HASH or HASH ref with values from RGB or any other space: |
|
30
|
|
|
|
|
|
|
new(r => 255, g => 0, b => 0) or new({ hue => 0, saturation => 100, lightness => 50 }) |
|
31
|
|
|
|
|
|
|
EOH |
|
32
|
86
|
|
|
|
|
312
|
my $first_arg_is_color_space = Graphics::Toolkit::Color::Space::Hub::is_space_name( $args[0] ); |
|
33
|
86
|
100
|
100
|
|
|
343
|
@args = ([ $args[0], @{$args[1]} ]) if @args == 2 and $first_arg_is_color_space and ref $args[1] eq 'ARRAY'; |
|
|
2
|
|
66
|
|
|
7
|
|
|
34
|
86
|
100
|
100
|
|
|
430
|
@args = ([ @args ]) if @args == 3 or (@args > 3 and $first_arg_is_color_space); |
|
|
|
|
100
|
|
|
|
|
|
35
|
86
|
100
|
100
|
|
|
465
|
@args = ({ @args }) if @args == 6 or @args == 8; |
|
36
|
86
|
100
|
|
|
|
262
|
return $help unless @args == 1; |
|
37
|
77
|
|
|
|
|
192
|
my $self = _new_from_scalar_def( $args[0] ); |
|
38
|
77
|
100
|
|
|
|
682
|
return (ref $self) ? $self : $help; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
sub _new_from_scalar_def { # color defs of method arguments |
|
41
|
135
|
|
|
135
|
|
230
|
my ($color_def) = shift; |
|
42
|
135
|
100
|
|
|
|
344
|
return $color_def if ref $color_def eq __PACKAGE__; |
|
43
|
117
|
|
|
|
|
551
|
return _new_from_value_obj( Graphics::Toolkit::Color::Values->new_from_any_input( $color_def ) ); |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
sub _new_from_value_obj { |
|
46
|
285
|
|
|
285
|
|
439
|
my ($value_obj) = @_; |
|
47
|
285
|
100
|
|
|
|
656
|
return $value_obj unless ref $value_obj eq 'Graphics::Toolkit::Color::Values'; |
|
48
|
238
|
|
|
|
|
1146
|
return bless {values => $value_obj}; |
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
## deprecated methods - deleted with 2.0 |
|
53
|
0
|
0
|
|
0
|
0
|
0
|
sub string { $_[0]{'name'} || $_[0]->{'values'}->string } |
|
54
|
0
|
|
|
0
|
0
|
0
|
sub rgb { $_[0]->values( ) } |
|
55
|
0
|
|
|
0
|
0
|
0
|
sub red {($_[0]->values( ))[0] } |
|
56
|
0
|
|
|
0
|
0
|
0
|
sub green {($_[0]->values( ))[1] } |
|
57
|
0
|
|
|
0
|
0
|
0
|
sub blue {($_[0]->values( ))[2] } |
|
58
|
0
|
|
|
0
|
0
|
0
|
sub rgb_hex { $_[0]->values( as => 'hex') } |
|
59
|
0
|
|
|
0
|
0
|
0
|
sub rgb_hash { $_[0]->values( as => 'hash') } |
|
60
|
0
|
|
|
0
|
0
|
0
|
sub hsl { $_[0]->values( in => 'hsl') } |
|
61
|
0
|
|
|
0
|
0
|
0
|
sub hue {($_[0]->values( in => 'hsl'))[0] } |
|
62
|
0
|
|
|
0
|
0
|
0
|
sub set { shift->set_value( @_ ) } |
|
63
|
0
|
|
|
0
|
0
|
0
|
sub add { shift->add_value( @_ ) } |
|
64
|
0
|
|
|
0
|
0
|
0
|
sub saturation {($_[0]->values( in => 'hsl'))[1] } |
|
65
|
0
|
|
|
0
|
0
|
0
|
sub lightness {($_[0]->values( in => 'hsl'))[2] } |
|
66
|
0
|
|
|
0
|
0
|
0
|
sub hsl_hash { $_[0]->values( in => 'hsl', as => 'hash') } |
|
67
|
0
|
|
|
0
|
0
|
0
|
sub distance_to { distance(@_) } |
|
68
|
0
|
|
|
0
|
0
|
0
|
sub blend { mix( @_ ) } |
|
69
|
0
|
|
|
0
|
0
|
0
|
sub blend_with { $_[0]->mix( with => $_[1], amount => $_[2], in => 'HSL') } |
|
70
|
0
|
|
|
0
|
0
|
0
|
sub gradient_to { hsl_gradient_to( @_ ) } |
|
71
|
0
|
|
|
0
|
0
|
0
|
sub rgb_gradient_to { $_[0]->gradient( to => $_[1], steps => $_[2], dynamic => $_[3], in => 'RGB' ) } |
|
72
|
0
|
|
|
0
|
0
|
0
|
sub hsl_gradient_to { $_[0]->gradient( to => $_[1], steps => $_[2], dynamic => $_[3], in => 'HSL' ) } |
|
73
|
0
|
|
|
0
|
0
|
0
|
sub complementary { complement(@_) } |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub _split_named_args { |
|
76
|
158
|
|
|
158
|
|
408
|
my ($raw_args, $only_parameter, $required_parameter, $optional_parameter, $parameter_alias) = @_; |
|
77
|
158
|
50
|
66
|
|
|
614
|
@$raw_args = %{$raw_args->[0]} if @$raw_args == 1 and ref $raw_args->[0] eq 'HASH' and not |
|
|
0
|
|
0
|
|
|
0
|
|
|
|
|
|
33
|
|
|
|
|
|
78
|
|
|
|
|
|
|
(defined $only_parameter and $only_parameter eq 'to' and ref _new_from_scalar_def( $raw_args ) ); |
|
79
|
|
|
|
|
|
|
|
|
80
|
158
|
100
|
100
|
|
|
422
|
if (@$raw_args == 1 and defined $only_parameter and $only_parameter){ |
|
|
|
|
66
|
|
|
|
|
|
81
|
33
|
50
|
|
|
|
58
|
return "The one default argument can not cover multiple, required parameter !" if @$required_parameter > 1; |
|
82
|
33
|
50
|
66
|
|
|
80
|
return "The default argument does not cover the required argument!" |
|
83
|
|
|
|
|
|
|
if @$required_parameter and $required_parameter->[0] ne $only_parameter; |
|
84
|
|
|
|
|
|
|
|
|
85
|
33
|
|
|
|
|
103
|
my %defaults = %$optional_parameter; |
|
86
|
33
|
|
|
|
|
62
|
delete $defaults{$only_parameter}; |
|
87
|
33
|
|
|
|
|
186
|
return {$only_parameter => $raw_args->[0], %defaults}; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
125
|
|
|
|
|
168
|
my %clean_arg; |
|
90
|
125
|
100
|
|
|
|
313
|
if (@$raw_args % 2) { |
|
91
|
2
|
50
|
33
|
|
|
15
|
return (defined $only_parameter and $only_parameter) |
|
92
|
|
|
|
|
|
|
? "Got odd number of values, please use key value pairs as arguments or one default argument !\n" |
|
93
|
|
|
|
|
|
|
: "Got odd number of values, please use key value pairs as arguments !\n" |
|
94
|
|
|
|
|
|
|
} |
|
95
|
123
|
|
|
|
|
288
|
my %arg_hash = @$raw_args; |
|
96
|
123
|
|
|
|
|
282
|
for my $parameter_name (@$required_parameter){ |
|
97
|
67
|
100
|
66
|
|
|
331
|
if (ref $parameter_alias eq 'HASH' and exists $parameter_alias->{ $parameter_name } |
|
|
|
|
66
|
|
|
|
|
|
98
|
|
|
|
|
|
|
and exists $arg_hash{ $parameter_alias->{$parameter_name} }){ |
|
99
|
10
|
|
|
|
|
57
|
$arg_hash{ $parameter_name } = delete $arg_hash{ $parameter_alias->{$parameter_name} }; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
67
|
100
|
|
|
|
199
|
return "Argument '$parameter_name' is missing\n" unless exists $arg_hash{$parameter_name}; |
|
102
|
61
|
|
|
|
|
175
|
$clean_arg{ $parameter_name } = delete $arg_hash{ $parameter_name }; |
|
103
|
|
|
|
|
|
|
} |
|
104
|
117
|
|
|
|
|
307
|
for my $parameter_name (keys %$optional_parameter){ |
|
105
|
382
|
50
|
66
|
|
|
699
|
if (ref $parameter_alias eq 'HASH' and exists $parameter_alias->{ $parameter_name } |
|
|
|
|
33
|
|
|
|
|
|
106
|
|
|
|
|
|
|
and exists $arg_hash{ $parameter_alias->{$parameter_name} }){ |
|
107
|
0
|
|
|
|
|
0
|
$arg_hash{ $parameter_name } = delete $arg_hash{ $parameter_alias->{$parameter_name} }; |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
$clean_arg{ $parameter_name } = exists $arg_hash{$parameter_name} |
|
110
|
|
|
|
|
|
|
? delete $arg_hash{ $parameter_name } |
|
111
|
382
|
100
|
|
|
|
1062
|
: $optional_parameter->{ $parameter_name }; |
|
112
|
|
|
|
|
|
|
} |
|
113
|
117
|
100
|
|
|
|
322
|
return "Inserted unknown argument(s): ".(join ',', keys %arg_hash)."\n" if %arg_hash; |
|
114
|
110
|
|
|
|
|
280
|
return \%clean_arg; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
## getter ############################################################## |
|
118
|
|
|
|
|
|
|
sub values { |
|
119
|
56
|
|
|
56
|
1
|
51622
|
my ($self, @args) = @_; |
|
120
|
56
|
|
|
|
|
432
|
my $arg = _split_named_args( \@args, 'in', [], |
|
121
|
|
|
|
|
|
|
{ in => $default_space_name, as => 'list', |
|
122
|
|
|
|
|
|
|
precision => undef, range => undef, suffix => undef } ); |
|
123
|
56
|
|
|
|
|
200
|
my $help = <
|
|
124
|
|
|
|
|
|
|
GTC method 'values' accepts either no arguments, one color space name or four optional, named args: |
|
125
|
|
|
|
|
|
|
values ( ... |
|
126
|
|
|
|
|
|
|
in => 'HSL', # color space name, defaults to "$default_space_name" |
|
127
|
|
|
|
|
|
|
as => 'css_string', # output format name, default is "list" |
|
128
|
|
|
|
|
|
|
range => 1, # value range (SCALAR or ARRAY), default set by space def |
|
129
|
|
|
|
|
|
|
precision => 3, # value precision (SCALAR or ARRAY), default set by space |
|
130
|
|
|
|
|
|
|
suffix => '%', # value suffix (SCALAR or ARRAY), default set by color space |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
EOH |
|
133
|
56
|
100
|
|
|
|
165
|
return $arg.$help unless ref $arg; |
|
134
|
55
|
|
|
|
|
304
|
$self->{'values'}->formatted( @$arg{qw/in as suffix range precision/} ); |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub name { |
|
138
|
34
|
|
|
34
|
1
|
10481
|
my ($self, @args) = @_; |
|
139
|
34
|
100
|
|
|
|
168
|
return $self->{'values'}->name unless @args; |
|
140
|
2
|
|
|
|
|
19
|
my $arg = _split_named_args( \@args, 'from', [], {from => 'default', all => 0, full => 0, distance => 0}); |
|
141
|
2
|
|
|
|
|
9
|
my $help = <
|
|
142
|
|
|
|
|
|
|
GTC method 'name' accepts three optional, named arguments: |
|
143
|
|
|
|
|
|
|
name ( ... |
|
144
|
|
|
|
|
|
|
'CSS' # color naming scheme works as only positional argument |
|
145
|
|
|
|
|
|
|
from => 'CSS' # same scheme (defaults to internal: X + CSS + PantoneReport) |
|
146
|
|
|
|
|
|
|
from => ['SVG', 'X'] # more color naming schemes at once, without duplicates |
|
147
|
|
|
|
|
|
|
all => 1 # returns list of all names with the object's RGB values (defaults 0) |
|
148
|
|
|
|
|
|
|
full => 1 # adds color scheme name to the color name. 'SVG:red' (defaults 0) |
|
149
|
|
|
|
|
|
|
distance => 3 # color names from within distance of 3 (defaults 0) |
|
150
|
|
|
|
|
|
|
EOH |
|
151
|
2
|
|
|
|
|
11
|
return Graphics::Toolkit::Color::Name::from_values( $self->{'values'}->shaped, @$arg{qw/from all full distance/}); |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
sub closest_name { |
|
155
|
11
|
|
|
11
|
1
|
17539
|
my ($self, @args) = @_; |
|
156
|
11
|
|
|
|
|
81
|
my $arg = _split_named_args( \@args, 'from', [], {from => 'default', all => 0, full => 0}); |
|
157
|
11
|
|
|
|
|
63
|
my $help = <
|
|
158
|
|
|
|
|
|
|
GTC method 'name' accepts three optional, named arguments: |
|
159
|
|
|
|
|
|
|
closest_name ( ... |
|
160
|
|
|
|
|
|
|
'CSS' # color naming scheme works as only positional argument |
|
161
|
|
|
|
|
|
|
from => 'CSS' # same scheme (defaults to internal: X + CSS + PantoneReport) |
|
162
|
|
|
|
|
|
|
from => ['SVG', 'X'] # more color naming schemes at once, without duplicates |
|
163
|
|
|
|
|
|
|
all => 1 # returns list of all names with the object's RGB values (defaults 0) |
|
164
|
|
|
|
|
|
|
full => 1 # adds color scheme name to the color name. 'SVG:red' (defaults 0) |
|
165
|
|
|
|
|
|
|
EOH |
|
166
|
|
|
|
|
|
|
my ($name, $distance) = Graphics::Toolkit::Color::Name::closest_from_values( |
|
167
|
11
|
|
|
|
|
59
|
$self->{'values'}->shaped, @$arg{qw/from all full/}); |
|
168
|
11
|
100
|
|
|
|
97
|
return wantarray ? ($name, $distance) : $name; |
|
169
|
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub distance { |
|
172
|
9
|
|
|
9
|
1
|
2984
|
my ($self, @args) = @_; |
|
173
|
9
|
|
|
|
|
69
|
my $arg = _split_named_args( \@args, 'to', ['to'], {in => $default_space_name, select => undef, range => undef}); |
|
174
|
9
|
|
|
|
|
37
|
my $help = <
|
|
175
|
|
|
|
|
|
|
GTC method 'distance' accepts as arguments either a scalar color definition or |
|
176
|
|
|
|
|
|
|
four named arguments, only the first being required: |
|
177
|
|
|
|
|
|
|
distance ( ... |
|
178
|
|
|
|
|
|
|
to => 'green' # color object or color definition (required) |
|
179
|
|
|
|
|
|
|
in => 'HSL' # color space name, defaults to "$default_space_name" |
|
180
|
|
|
|
|
|
|
select => 'red' # axis name or names (ARRAY ref), default is none |
|
181
|
|
|
|
|
|
|
range => 2**16 # value range definition, defaults come from color space def |
|
182
|
|
|
|
|
|
|
EOH |
|
183
|
9
|
100
|
|
|
|
34
|
return $arg.$help unless ref $arg; |
|
184
|
7
|
|
|
|
|
24
|
my $target_color = _new_from_scalar_def( $arg->{'to'} ); |
|
185
|
7
|
50
|
|
|
|
19
|
return "target color definition: $arg->{to} is ill formed" unless ref $target_color; |
|
186
|
7
|
|
|
|
|
25
|
my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $arg->{'in'} ); |
|
187
|
7
|
50
|
|
|
|
15
|
return "$color_space\n".$help unless ref $color_space; |
|
188
|
7
|
100
|
|
|
|
26
|
if (defined $arg->{'select'}){ |
|
189
|
3
|
100
|
|
|
|
13
|
if (not ref $arg->{'select'}){ |
|
|
|
50
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
return $arg->{'select'}." is not an axis name in color space: ".$color_space->name |
|
191
|
2
|
50
|
|
|
|
11
|
unless $color_space->is_axis_name( $arg->{'select'} ); |
|
192
|
|
|
|
|
|
|
} elsif (ref $arg->{'select'} eq 'ARRAY'){ |
|
193
|
1
|
|
|
|
|
3
|
for my $axis_name (@{$arg->{'select'}}) { |
|
|
1
|
|
|
|
|
5
|
|
|
194
|
2
|
50
|
|
|
|
6
|
return "$axis_name is not an axis name in color space: ".$color_space->name |
|
195
|
|
|
|
|
|
|
unless $color_space->is_axis_name( $axis_name ); |
|
196
|
|
|
|
|
|
|
} |
|
197
|
0
|
|
|
|
|
0
|
} else { return "The 'select' argument needs one axis name or an ARRAY with several axis names". |
|
198
|
|
|
|
|
|
|
" from the same color space!" } |
|
199
|
|
|
|
|
|
|
} |
|
200
|
7
|
|
|
|
|
25
|
my $range_def = $color_space->shape->try_check_range_definition( $arg->{'range'} ); |
|
201
|
7
|
50
|
|
|
|
17
|
return $range_def unless ref $range_def; |
|
202
|
|
|
|
|
|
|
Graphics::Toolkit::Color::Space::Hub::distance( |
|
203
|
7
|
|
|
|
|
34
|
$self->{'values'}->normalized, $target_color->{'values'}->normalized, $color_space->name ,$arg->{'select'}, $range_def ); |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
## single color creation methods ####################################### |
|
207
|
|
|
|
|
|
|
sub set_value { |
|
208
|
10
|
|
|
10
|
1
|
6502
|
my ($self, @args) = @_; |
|
209
|
10
|
50
|
33
|
|
|
30
|
@args = %{$args[0]} if @args == 1 and ref $args[0] eq 'HASH'; |
|
|
0
|
|
|
|
|
0
|
|
|
210
|
10
|
|
|
|
|
13
|
my $help = <
|
|
211
|
|
|
|
|
|
|
GTC method 'set_value' needs a value HASH (not a ref) whose keys are axis names or |
|
212
|
|
|
|
|
|
|
short names from one color space. If the chosen axis name(s) is/are ambiguous, |
|
213
|
|
|
|
|
|
|
you might add the "in" argument: |
|
214
|
|
|
|
|
|
|
set_value( green => 20 ) or set( g => 20 ) or |
|
215
|
|
|
|
|
|
|
set_value( hue => 240, in => 'HWB' ) |
|
216
|
|
|
|
|
|
|
EOH |
|
217
|
10
|
100
|
66
|
|
|
71
|
return $help if @args % 2 or not @args or @args > 10; |
|
|
|
|
66
|
|
|
|
|
|
218
|
9
|
|
|
|
|
23
|
my $partial_color = { @args }; |
|
219
|
9
|
|
|
|
|
14
|
my $space_name = delete $partial_color->{'in'}; |
|
220
|
9
|
|
|
|
|
19
|
my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $space_name ); |
|
221
|
9
|
50
|
|
|
|
14
|
return "$color_space\n".$help unless ref $color_space; |
|
222
|
9
|
|
|
|
|
82
|
_new_from_value_obj( $self->{'values'}->set( $partial_color, $space_name ) ); |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub add_value { |
|
226
|
10
|
|
|
10
|
1
|
6593
|
my ($self, @args) = @_; |
|
227
|
10
|
50
|
33
|
|
|
28
|
@args = %{$args[0]} if @args == 1 and ref $args[0] eq 'HASH'; |
|
|
0
|
|
|
|
|
0
|
|
|
228
|
10
|
|
|
|
|
16
|
my $help = <
|
|
229
|
|
|
|
|
|
|
GTC method 'add_value' needs a value HASH (not a ref) whose keys are axis names or |
|
230
|
|
|
|
|
|
|
short names from one color space. If the chosen axis name(s) is/are ambiguous, |
|
231
|
|
|
|
|
|
|
you might add the "in" argument: |
|
232
|
|
|
|
|
|
|
add_value( blue => -10 ) or set( b => -10 ) |
|
233
|
|
|
|
|
|
|
add_value( hue => 100 , in => 'HWB' ) |
|
234
|
|
|
|
|
|
|
EOH |
|
235
|
10
|
100
|
66
|
|
|
54
|
return $help if @args % 2 or not @args or @args > 10; |
|
|
|
|
66
|
|
|
|
|
|
236
|
9
|
|
|
|
|
20
|
my $partial_color = { @args }; |
|
237
|
9
|
|
|
|
|
13
|
my $space_name = delete $partial_color->{'in'}; |
|
238
|
9
|
|
|
|
|
22
|
my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $space_name ); |
|
239
|
9
|
50
|
|
|
|
15
|
return "$color_space\n".$help unless ref $color_space; |
|
240
|
9
|
|
|
|
|
30
|
_new_from_value_obj( $self->{'values'}->add( $partial_color, $space_name ) ); |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub mix { |
|
244
|
23
|
|
|
23
|
1
|
15565
|
my ($self, @args) = @_; |
|
245
|
23
|
|
|
|
|
110
|
my $arg = _split_named_args( \@args, 'to', ['to'], {in => $default_space_name, amount => 50}); |
|
246
|
23
|
|
|
|
|
83
|
my $help = <
|
|
247
|
|
|
|
|
|
|
GTC method 'mix' accepts three named arguments, only the first being required: |
|
248
|
|
|
|
|
|
|
mix ( ... |
|
249
|
|
|
|
|
|
|
to => ['HSL', 240, 100, 50] # scalar color definition or ARRAY ref thereof |
|
250
|
|
|
|
|
|
|
amount => 20 # percentage value or ARRAY ref thereof, default is 50 |
|
251
|
|
|
|
|
|
|
in => 'HSL' # color space name, defaults to "$default_space_name" |
|
252
|
|
|
|
|
|
|
Please note that either both or none of the first two arguments has to be an ARRAY. |
|
253
|
|
|
|
|
|
|
Both ARRAY have to have the same length. 'amount' refers to the color(s) picked with 'to'. |
|
254
|
|
|
|
|
|
|
EOH |
|
255
|
23
|
100
|
|
|
|
62
|
return $arg.$help unless ref $arg; |
|
256
|
21
|
|
|
|
|
49
|
my $recipe = _new_from_scalar_def( $arg->{'to'} ); |
|
257
|
21
|
100
|
|
|
|
36
|
if (ref $recipe){ |
|
258
|
11
|
|
|
|
|
31
|
$recipe = [{color => $recipe->{'values'}, percent => 50}]; |
|
259
|
11
|
100
|
|
|
|
31
|
return "Amount argument has to be a sacalar value if only one color is mixed !\n".$help if ref $arg->{'amount'}; |
|
260
|
10
|
50
|
|
|
|
30
|
$recipe->[0]{'percent'} = $arg->{'amount'} if defined $arg->{'amount'}; |
|
261
|
|
|
|
|
|
|
} else { |
|
262
|
10
|
100
|
|
|
|
29
|
if (ref $arg->{'to'} ne 'ARRAY'){ |
|
263
|
2
|
|
|
|
|
40
|
return "target color definition (argument 'to'): $arg->{to} is ill formed, has to be one color definition or an ARRAY of"; |
|
264
|
|
|
|
|
|
|
} else { |
|
265
|
8
|
|
|
|
|
15
|
$recipe = []; |
|
266
|
8
|
|
|
|
|
10
|
for my $color_def (@{$arg->{'to'}}){ |
|
|
8
|
|
|
|
|
20
|
|
|
267
|
13
|
|
|
|
|
21
|
my $color = _new_from_scalar_def( $color_def ); |
|
268
|
13
|
50
|
|
|
|
23
|
return "target color definition: '$color_def' is ill formed" unless ref $color; |
|
269
|
13
|
|
|
|
|
56
|
push @$recipe, { color => $color->{'values'}, percent => 50}; |
|
270
|
|
|
|
|
|
|
} |
|
271
|
|
|
|
|
|
|
return "Amount argument has to be an ARRAY of same length as argument 'to' (color definitions)!\n".$help |
|
272
|
8
|
100
|
66
|
|
|
45
|
if ref $arg->{'to'} eq 'ARRAY' and ref $arg->{'amount'} eq 'ARRAY' and @{$arg->{'amount'}} != @{$arg->{'to'}}; |
|
|
3
|
|
100
|
|
|
6
|
|
|
|
3
|
|
|
|
|
21
|
|
|
273
|
7
|
100
|
66
|
|
|
67
|
$arg->{'amount'} = [($arg->{'amount'}) x @{$arg->{'to'}}] if ref $arg->{'to'} and not ref $arg->{'amount'}; |
|
|
5
|
|
|
|
|
11
|
|
|
274
|
7
|
|
|
|
|
11
|
$recipe->[$_]{'percent'} = $arg->{'amount'}[$_] for 0 .. $#{$arg->{'amount'}}; |
|
|
7
|
|
|
|
|
31
|
|
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
} |
|
277
|
17
|
|
|
|
|
42
|
my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( delete $arg->{'in'} ); |
|
278
|
17
|
100
|
|
|
|
45
|
return "$color_space\n".$help unless ref $color_space; |
|
279
|
16
|
|
|
|
|
45
|
_new_from_value_obj( $self->{'values'}->mix( $recipe, $color_space ) ); |
|
280
|
|
|
|
|
|
|
} |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub invert { |
|
283
|
13
|
|
|
13
|
1
|
40
|
my ($self, @args) = @_; |
|
284
|
13
|
|
|
|
|
78
|
my $arg = _split_named_args( \@args, 'in', [], {in => $default_space_name}); |
|
285
|
13
|
|
|
|
|
33
|
my $help = <
|
|
286
|
|
|
|
|
|
|
GTC method 'invert' accepts one optional argument, which can be positional or named: |
|
287
|
|
|
|
|
|
|
invert ( ... |
|
288
|
|
|
|
|
|
|
in => 'HSL' # color space name, defaults to "$default_space_name" |
|
289
|
|
|
|
|
|
|
EOH |
|
290
|
13
|
100
|
|
|
|
30
|
return $arg.$help unless ref $arg; |
|
291
|
12
|
|
|
|
|
28
|
my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $arg->{'in'} ); |
|
292
|
12
|
100
|
|
|
|
27
|
return "$color_space\n".$help unless ref $color_space; |
|
293
|
11
|
|
|
|
|
43
|
_new_from_value_obj( $self->{'values'}->invert( $color_space ) ); |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
## color set creation methods ########################################## |
|
297
|
|
|
|
|
|
|
sub complement { |
|
298
|
12
|
|
|
12
|
1
|
676
|
my ($self, @args) = @_; |
|
299
|
12
|
|
|
|
|
54
|
my $arg = _split_named_args( \@args, 'steps', [], {steps => 1, tilt => 0, target => {}}); |
|
300
|
12
|
|
|
|
|
27
|
my $help = <
|
|
301
|
|
|
|
|
|
|
GTC method 'complement' is computed in HSL and has two named, optional arguments: |
|
302
|
|
|
|
|
|
|
complement ( ... |
|
303
|
|
|
|
|
|
|
steps => 20 # count of produced colors, default is 1 |
|
304
|
|
|
|
|
|
|
tilt => 10 # default is 0 |
|
305
|
|
|
|
|
|
|
target => {h => 10, s => 20, l => 3} # sub-keys are independent, default to 0 |
|
306
|
|
|
|
|
|
|
EOH |
|
307
|
12
|
100
|
|
|
|
29
|
return $arg.$help unless ref $arg; |
|
308
|
11
|
100
|
|
|
|
32
|
return "Optional argument 'steps' has to be a number !\n".$help unless is_nr($arg->{'steps'}); |
|
309
|
9
|
50
|
|
|
|
34
|
return "Optional argument 'steps' is zero, no complement colors will be computed !\n".$help unless $arg->{'steps'}; |
|
310
|
9
|
100
|
|
|
|
17
|
return "Optional argument 'tilt' has to be a number !\n".$help unless is_nr($arg->{'tilt'}); |
|
311
|
8
|
100
|
|
|
|
23
|
return "Optional argument 'target' has to be a HASH ref !\n".$help if ref $arg->{'target'} ne 'HASH'; |
|
312
|
7
|
|
|
|
|
9
|
my ($target_values, $space_name); |
|
313
|
7
|
100
|
|
|
|
8
|
if (keys %{$arg->{'target'}}){ |
|
|
7
|
|
|
|
|
17
|
|
|
314
|
2
|
|
|
|
|
8
|
($target_values, $space_name) = Graphics::Toolkit::Color::Space::Hub::deformat_partial_hash( $arg->{'target'}, 'HSL' ); |
|
315
|
2
|
100
|
|
|
|
14
|
return "Optional argument 'target' got HASH keys that do not fit HSL space (use 'h','s','l') !\n".$help |
|
316
|
|
|
|
|
|
|
unless ref $target_values; |
|
317
|
5
|
|
|
|
|
10
|
} else { $target_values = [] } |
|
318
|
13
|
|
|
|
|
27
|
map {_new_from_value_obj( $_ )} |
|
319
|
6
|
|
|
|
|
27
|
Graphics::Toolkit::Color::SetCalculator::complement( $self->{'values'}, @$arg{qw/steps tilt/}, $target_values ); |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub gradient { |
|
323
|
14
|
|
|
14
|
1
|
1927
|
my ($self, @args) = @_; |
|
324
|
14
|
|
|
|
|
92
|
my $arg = _split_named_args( \@args, 'to', ['to'], {steps => 10, tilt => 0, in => $default_space_name}); |
|
325
|
14
|
|
|
|
|
49
|
my $help = <
|
|
326
|
|
|
|
|
|
|
GTC method 'gradient' accepts four named arguments, only the first is required: |
|
327
|
|
|
|
|
|
|
gradient ( ... |
|
328
|
|
|
|
|
|
|
to => 'blue' # scalar color definition or ARRAY ref thereof |
|
329
|
|
|
|
|
|
|
steps => 20 # count of produced colors, defaults to 10 |
|
330
|
|
|
|
|
|
|
tilt => 1 # dynamics of color change, defaults to 0 |
|
331
|
|
|
|
|
|
|
in => 'HSL' # color space name, defaults to "$default_space_name" |
|
332
|
|
|
|
|
|
|
EOH |
|
333
|
14
|
100
|
|
|
|
47
|
return $arg.$help unless ref $arg; |
|
334
|
12
|
|
|
|
|
33
|
my @colors = ($self->{'values'}); |
|
335
|
12
|
|
|
|
|
37
|
my $target_color = _new_from_scalar_def( $arg->{'to'} ); |
|
336
|
12
|
100
|
|
|
|
29
|
if (ref $target_color) { |
|
337
|
9
|
|
|
|
|
26
|
push @colors, $target_color->{'values'} } |
|
338
|
|
|
|
|
|
|
else { |
|
339
|
3
|
100
|
66
|
|
|
22
|
return "Argument 'to' contains malformed color definition!\n".$help if ref $arg->{'to'} ne 'ARRAY' or not @{$arg->{'to'}}; |
|
|
2
|
|
|
|
|
9
|
|
|
340
|
2
|
|
|
|
|
6
|
for my $color_def (@{$arg->{'to'}}){ |
|
|
2
|
|
|
|
|
6
|
|
|
341
|
5
|
|
|
|
|
10
|
my $target_color = _new_from_scalar_def( $color_def ); |
|
342
|
5
|
100
|
|
|
|
47
|
return "Argument 'to' contains malformed color definition: $color_def !\n".$help unless ref $target_color; |
|
343
|
4
|
|
|
|
|
17
|
push @colors, $target_color->{'values'}; |
|
344
|
|
|
|
|
|
|
} |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
return "Argument 'steps' has to be a number greater zero !\n".$help |
|
347
|
10
|
100
|
66
|
|
|
26
|
unless is_nr($arg->{'steps'}) and $arg->{'steps'} > 0; |
|
348
|
9
|
|
|
|
|
25
|
$arg->{'steps'} = int $arg->{'steps'}; |
|
349
|
9
|
100
|
|
|
|
15
|
return "Argument 'tilt' has to be a number !\n".$help unless is_nr($arg->{'tilt'}); |
|
350
|
8
|
|
|
|
|
23
|
my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $arg->{'in'} ); |
|
351
|
8
|
100
|
|
|
|
38
|
return "$color_space\n".$help unless ref $color_space; |
|
352
|
53
|
|
|
|
|
73
|
map {_new_from_value_obj( $_ )} |
|
353
|
7
|
|
|
|
|
32
|
Graphics::Toolkit::Color::SetCalculator::gradient( \@colors, @$arg{qw/steps tilt/}, $color_space); |
|
354
|
|
|
|
|
|
|
} |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub cluster { |
|
357
|
18
|
|
|
18
|
1
|
10367
|
my ($self, @args) = @_; |
|
358
|
18
|
|
|
|
|
130
|
my $arg = _split_named_args( \@args, undef, ['radius', 'minimal_distance'], {in => $default_space_name}, |
|
359
|
|
|
|
|
|
|
{radius => 'r', minimal_distance => 'min_d'} ); |
|
360
|
18
|
|
|
|
|
75
|
my $help = <
|
|
361
|
|
|
|
|
|
|
GTC method 'cluster' accepts three named arguments, the first two being required: |
|
362
|
|
|
|
|
|
|
cluster ( ... |
|
363
|
|
|
|
|
|
|
radius => 3 # ball shaped cluster with cuboctahedral packing or |
|
364
|
|
|
|
|
|
|
r => [10, 5, 3] # cuboid shaped cluster with cubical packing |
|
365
|
|
|
|
|
|
|
minimal_distance => 0.5 # minimal distance between colors in cluster |
|
366
|
|
|
|
|
|
|
min_d => 0.5 # short alias for minimal distance |
|
367
|
|
|
|
|
|
|
in => 'HSL' # color space name, defaults to "$default_space_name" |
|
368
|
|
|
|
|
|
|
EOH |
|
369
|
18
|
100
|
|
|
|
87
|
return $arg.$help unless ref $arg; |
|
370
|
12
|
|
|
|
|
46
|
my $color_space = Graphics::Toolkit::Color::Space::Hub::try_get_space( $arg->{'in'} ); |
|
371
|
12
|
100
|
|
|
|
41
|
return "$color_space\n".$help unless ref $color_space; |
|
372
|
|
|
|
|
|
|
return "Argument 'radius' has to be a number or an ARRAY of numbers".$help |
|
373
|
11
|
100
|
100
|
|
|
38
|
unless is_nr($arg->{'radius'}) or $color_space->is_number_tuple( $arg->{'radius'} ); |
|
374
|
|
|
|
|
|
|
return "Argument 'distance' has to be a number greater zero !\n".$help |
|
375
|
8
|
100
|
100
|
|
|
25
|
unless is_nr($arg->{'minimal_distance'}) and $arg->{'minimal_distance'} > 0; |
|
376
|
|
|
|
|
|
|
return "Ball shaped cluster works only in spaces with three dimensions !\n".$help |
|
377
|
6
|
100
|
100
|
|
|
22
|
if $color_space->axis_count > 3 and not ref $arg->{'radius'}; |
|
378
|
57
|
|
|
|
|
68
|
map {_new_from_value_obj( $_ )} |
|
379
|
5
|
|
|
|
|
27
|
Graphics::Toolkit::Color::SetCalculator::cluster( $self->{'values'}, @$arg{qw/radius minimal_distance/}, $color_space); |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
1; |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
__END__ |