Update upstream source from tag 'upstream/2.403.8'
Update to upstream version '2.403.8'
with Debian dir cace1b0746386ae76a3d9d7bfb3fa7010829ac31
gregor herrmann
1 year, 5 months ago
0 | 2.403.8 2022-10-22 lichtkind | |
1 | -------- | |
2 | * = POD rewrite release | |
3 | * \ moved color code to Graphics::Toolkit::Color | |
4 | * ? adapted POD | |
5 | ||
0 | 6 | 2.403.7 2022-07-29 lichtkind |
1 | 7 | ------- |
2 | 8 | * = POD rewrite release |
13 | 13 | lib/Chart/Bars.pm |
14 | 14 | lib/Chart/Base.pm |
15 | 15 | lib/Chart/BrushStyles.pm |
16 | lib/Chart/Color.pm | |
17 | lib/Chart/Color/Constant.pm | |
18 | lib/Chart/Color/Value.pm | |
19 | 16 | lib/Chart/Composite.pm |
20 | 17 | lib/Chart/Constants.pm |
21 | 18 | lib/Chart/Direction.pm |
33 | 30 | lib/Chart/Pie.pm |
34 | 31 | lib/Chart/Points.pm |
35 | 32 | lib/Chart/Property.pm |
33 | lib/Chart/Property/DataType/Color.pm | |
36 | 34 | lib/Chart/Property/DataType/Font.pm |
37 | 35 | lib/Chart/Split.pm |
38 | 36 | lib/Chart/StackedBars.pm |
39 | t/001_color_value.t | |
40 | t/002_color_constant.t | |
41 | t/003_color.t | |
42 | 37 | t/Humidity.t |
43 | 38 | t/Math_1_over_x.t |
44 | 39 | t/bars.t |
17 | 17 | "t" |
18 | 18 | ], |
19 | 19 | "namespace" : [ |
20 | "Chart::Color", | |
21 | "Chart::Manual" | |
20 | "Chart::Manual", | |
21 | "Chart::Property" | |
22 | 22 | ], |
23 | 23 | "package" : [ |
24 | 24 | "Chart::Base", |
36 | 36 | "requires" : { |
37 | 37 | "Carp" : "1.35", |
38 | 38 | "GD" : "2", |
39 | "Graphics::Toolkit::Color" : "1", | |
39 | 40 | "perl" : "v5.12.0" |
40 | 41 | }, |
41 | 42 | "suggests" : { |
53 | 54 | "provides" : { |
54 | 55 | "Chart" : { |
55 | 56 | "file" : "lib/Chart.pm", |
56 | "version" : "v2.403.7" | |
57 | "version" : "v2.403.8" | |
57 | 58 | }, |
58 | 59 | "Chart::Bars" : { |
59 | 60 | "file" : "lib/Chart/Bars.pm", |
60 | "version" : "v2.403.7" | |
61 | }, | |
62 | "Chart::Color" : { | |
63 | "file" : "lib/Chart/Color.pm", | |
64 | "version" : "v2.403.7" | |
61 | "version" : "v2.403.8" | |
65 | 62 | }, |
66 | 63 | "Chart::Composite" : { |
67 | 64 | "file" : "lib/Chart/Composite.pm", |
68 | "version" : "v2.403.7" | |
65 | "version" : "v2.403.8" | |
69 | 66 | }, |
70 | 67 | "Chart::Direction" : { |
71 | 68 | "file" : "lib/Chart/Direction.pm", |
72 | "version" : "v2.403.7" | |
69 | "version" : "v2.403.8" | |
73 | 70 | }, |
74 | 71 | "Chart::ErrorBars" : { |
75 | 72 | "file" : "lib/Chart/ErrorBars.pm", |
76 | "version" : "v2.403.7" | |
73 | "version" : "v2.403.8" | |
77 | 74 | }, |
78 | 75 | "Chart::HorizontalBars" : { |
79 | 76 | "file" : "lib/Chart/HorizontalBars.pm", |
80 | "version" : "v2.403.7" | |
77 | "version" : "v2.403.8" | |
81 | 78 | }, |
82 | 79 | "Chart::Lines" : { |
83 | 80 | "file" : "lib/Chart/Lines.pm", |
84 | "version" : "v2.403.7" | |
81 | "version" : "v2.403.8" | |
85 | 82 | }, |
86 | 83 | "Chart::LinesPoints" : { |
87 | 84 | "file" : "lib/Chart/LinesPoints.pm", |
88 | "version" : "v2.403.7" | |
85 | "version" : "v2.403.8" | |
89 | 86 | }, |
90 | 87 | "Chart::Mountain" : { |
91 | 88 | "file" : "lib/Chart/Mountain.pm", |
92 | "version" : "v2.403.7" | |
89 | "version" : "v2.403.8" | |
93 | 90 | }, |
94 | 91 | "Chart::Pareto" : { |
95 | 92 | "file" : "lib/Chart/Pareto.pm", |
96 | "version" : "v2.403.7" | |
93 | "version" : "v2.403.8" | |
97 | 94 | }, |
98 | 95 | "Chart::Pie" : { |
99 | 96 | "file" : "lib/Chart/Pie.pm", |
100 | "version" : "v2.403.7" | |
97 | "version" : "v2.403.8" | |
101 | 98 | }, |
102 | 99 | "Chart::Points" : { |
103 | 100 | "file" : "lib/Chart/Points.pm", |
104 | "version" : "v2.403.7" | |
101 | "version" : "v2.403.8" | |
105 | 102 | }, |
106 | 103 | "Chart::Property" : { |
107 | 104 | "file" : "lib/Chart/Property.pm", |
108 | "version" : "v2.403.7" | |
109 | }, | |
110 | "Chart::Property::DataType::Font" : { | |
111 | "file" : "lib/Chart/Property/DataType/Font.pm", | |
112 | "version" : "v2.403.7" | |
105 | "version" : "v2.403.8" | |
113 | 106 | }, |
114 | 107 | "Chart::Split" : { |
115 | 108 | "file" : "lib/Chart/Split.pm", |
116 | "version" : "v2.403.7" | |
109 | "version" : "v2.403.8" | |
117 | 110 | }, |
118 | 111 | "Chart::StackedBars" : { |
119 | 112 | "file" : "lib/Chart/StackedBars.pm", |
120 | "version" : "v2.403.7" | |
113 | "version" : "v2.403.8" | |
121 | 114 | } |
122 | 115 | }, |
123 | 116 | "release_status" : "stable", |
128 | 121 | "web" : "https://github.com/lichtkind/Chart" |
129 | 122 | } |
130 | 123 | }, |
131 | "version" : "v2.403.7", | |
124 | "version" : "v2.403.8", | |
132 | 125 | "x_generated_by_perl" : "v5.30.0", |
133 | 126 | "x_maintainers" : [ |
134 | 127 | "Herbert Breunung <lichtkind@cpan.org>" |
18 | 18 | directory: |
19 | 19 | - t |
20 | 20 | namespace: |
21 | - Chart::Color | |
22 | 21 | - Chart::Manual |
22 | - Chart::Property | |
23 | 23 | package: |
24 | 24 | - Chart::Base |
25 | 25 | - Chart::BrushStyles |
27 | 27 | provides: |
28 | 28 | Chart: |
29 | 29 | file: lib/Chart.pm |
30 | version: v2.403.7 | |
30 | version: v2.403.8 | |
31 | 31 | Chart::Bars: |
32 | 32 | file: lib/Chart/Bars.pm |
33 | version: v2.403.7 | |
34 | Chart::Color: | |
35 | file: lib/Chart/Color.pm | |
36 | version: v2.403.7 | |
33 | version: v2.403.8 | |
37 | 34 | Chart::Composite: |
38 | 35 | file: lib/Chart/Composite.pm |
39 | version: v2.403.7 | |
36 | version: v2.403.8 | |
40 | 37 | Chart::Direction: |
41 | 38 | file: lib/Chart/Direction.pm |
42 | version: v2.403.7 | |
39 | version: v2.403.8 | |
43 | 40 | Chart::ErrorBars: |
44 | 41 | file: lib/Chart/ErrorBars.pm |
45 | version: v2.403.7 | |
42 | version: v2.403.8 | |
46 | 43 | Chart::HorizontalBars: |
47 | 44 | file: lib/Chart/HorizontalBars.pm |
48 | version: v2.403.7 | |
45 | version: v2.403.8 | |
49 | 46 | Chart::Lines: |
50 | 47 | file: lib/Chart/Lines.pm |
51 | version: v2.403.7 | |
48 | version: v2.403.8 | |
52 | 49 | Chart::LinesPoints: |
53 | 50 | file: lib/Chart/LinesPoints.pm |
54 | version: v2.403.7 | |
51 | version: v2.403.8 | |
55 | 52 | Chart::Mountain: |
56 | 53 | file: lib/Chart/Mountain.pm |
57 | version: v2.403.7 | |
54 | version: v2.403.8 | |
58 | 55 | Chart::Pareto: |
59 | 56 | file: lib/Chart/Pareto.pm |
60 | version: v2.403.7 | |
57 | version: v2.403.8 | |
61 | 58 | Chart::Pie: |
62 | 59 | file: lib/Chart/Pie.pm |
63 | version: v2.403.7 | |
60 | version: v2.403.8 | |
64 | 61 | Chart::Points: |
65 | 62 | file: lib/Chart/Points.pm |
66 | version: v2.403.7 | |
63 | version: v2.403.8 | |
67 | 64 | Chart::Property: |
68 | 65 | file: lib/Chart/Property.pm |
69 | version: v2.403.7 | |
70 | Chart::Property::DataType::Font: | |
71 | file: lib/Chart/Property/DataType/Font.pm | |
72 | version: v2.403.7 | |
66 | version: v2.403.8 | |
73 | 67 | Chart::Split: |
74 | 68 | file: lib/Chart/Split.pm |
75 | version: v2.403.7 | |
69 | version: v2.403.8 | |
76 | 70 | Chart::StackedBars: |
77 | 71 | file: lib/Chart/StackedBars.pm |
78 | version: v2.403.7 | |
72 | version: v2.403.8 | |
79 | 73 | requires: |
80 | 74 | Carp: '1.35' |
81 | 75 | GD: '2' |
76 | Graphics::Toolkit::Color: '1' | |
82 | 77 | perl: v5.12.0 |
83 | 78 | resources: |
84 | 79 | repository: git://github.com/lichtkind/Chart.git |
85 | version: v2.403.7 | |
80 | version: v2.403.8 | |
86 | 81 | x_generated_by_perl: v5.30.0 |
87 | 82 | x_maintainers: |
88 | 83 | - 'Herbert Breunung <lichtkind@cpan.org>' |
17 | 17 | "NAME" => "Chart", |
18 | 18 | "PREREQ_PM" => { |
19 | 19 | "Carp" => "1.35", |
20 | "GD" => 2 | |
20 | "GD" => 2, | |
21 | "Graphics::Toolkit::Color" => 1 | |
21 | 22 | }, |
22 | 23 | "TEST_REQUIRES" => { |
23 | 24 | "File::Temp" => "0.19", |
24 | 25 | "Test::More" => "1.3", |
25 | 26 | "Test::Warn" => "0.30" |
26 | 27 | }, |
27 | "VERSION" => "v2.403.7", | |
28 | "VERSION" => "v2.403.8", | |
28 | 29 | "test" => { |
29 | 30 | "TESTS" => "t/*.t" |
30 | 31 | } |
35 | 36 | "Carp" => "1.35", |
36 | 37 | "File::Temp" => "0.19", |
37 | 38 | "GD" => 2, |
39 | "Graphics::Toolkit::Color" => 1, | |
38 | 40 | "Test::More" => "1.3", |
39 | 41 | "Test::Warn" => "0.30" |
40 | 42 | ); |
2 | 2 | |
3 | 3 | requires "Carp" => "1.35"; |
4 | 4 | requires "GD" => "2"; |
5 | requires "Graphics::Toolkit::Color" => "1"; | |
5 | 6 | requires "perl" => "v5.12.0"; |
6 | 7 | suggests "Graphics::ColorNames" => "0"; |
7 | 8 |
14 | 14 | Carp = 1.35 |
15 | 15 | ;List::Util = 1.2 |
16 | 16 | GD = 2 |
17 | Graphics::Toolkit::Color = 1 | |
17 | 18 | |
18 | 19 | [Prereqs / RuntimeSuggests] |
19 | 20 | Graphics::ColorNames = 0 |
23 | 24 | Test::More = 1.3 |
24 | 25 | Test::Warn = 0.30 |
25 | 26 | |
26 | ||
27 | 27 | [MetaNoIndex] |
28 | 28 | directory = t |
29 | 29 | package = Chart::Base |
30 | 30 | package = Chart::Constants |
31 | 31 | package = Chart::BrushStyles |
32 | ;package = Chart::Font | |
33 | ;namespace = Chart::Setting | |
34 | namespace = Chart::Color | |
32 | namespace = Chart::Property | |
35 | 33 | namespace = Chart::Manual |
36 | 34 | |
37 | 35 | ; pollutes meta section 'provides' |
48 | 46 | ; use RewriteVersion or VersionFromModule |
49 | 47 | ;[VersionFromModule] |
50 | 48 | [RewriteVersion] |
49 | allow_decimal_underscore = 1 | |
50 | ||
51 | 51 | [Repository] |
52 | 52 | [AbstractFromPOD] |
53 | 53 | [Pod2Readme] |
4 | 4 | |
5 | 5 | package Chart::Bars; |
6 | 6 | our @ISA = qw(Chart::Base); |
7 | our $VERSION = 'v2.403.7'; | |
7 | our $VERSION = 'v2.403.8'; | |
8 | 8 | |
9 | 9 | use Chart::Base; |
10 | 10 | use GD; |
4 | 4 | use v5.12; |
5 | 5 | |
6 | 6 | package Chart::Base; |
7 | our $VERSION = 'v2.403.7'; | |
7 | our $VERSION = 'v2.403.8'; | |
8 | 8 | |
9 | 9 | use FileHandle; |
10 | 10 | use Carp; |
11 | 11 | use GD; |
12 | 12 | use GD::Image; |
13 | use Chart::Color; | |
14 | #use Property::DataType::Font; | |
13 | use Chart::Property::DataType::Color; | |
14 | #use Chart::Property::DataType::Font; | |
15 | 15 | |
16 | 16 | #>>>>>>>>>>>>>>>>>>>>>>>>>># |
17 | 17 | # public methods # |
1161 | 1161 | |
1162 | 1162 | sub _color_spec_to_rgb { |
1163 | 1163 | my ($self, $role, $spec) = @_; # color role name (from set) for error msg |
1164 | my $color = Chart::Color->new( $spec ); | |
1164 | my $color = Chart::Property::DataType::Color->new( $spec ); | |
1165 | 1165 | return croak "Unrecognized color for $role\n" unless ref $color; |
1166 | 1166 | $color->rgb; |
1167 | 1167 | } |
1245 | 1245 | |
1246 | 1246 | # now loop through the rest of them |
1247 | 1247 | # (the font is decreased in width and height by 1 |
1248 | if ( $w > 1 ) { $w--; } | |
1249 | if ( $h > 1 ) { $h--; } | |
1250 | for ( 1 .. $#lines ) | |
1251 | { | |
1248 | if ( $w > 1 ) { $w-- } | |
1249 | if ( $h > 1 ) { $h-- } | |
1250 | for ( 1 .. $#lines ) { | |
1252 | 1251 | $self->{'curr_y_min'} += $self->{'text_space'} + $h; |
1253 | 1252 | $x = ( $self->{'curr_x_max'} - $self->{'curr_x_min'} ) / 2 + $self->{'curr_x_min'} - ( length( $lines[$_] ) * $w ) / 2; |
1254 | 1253 | $y = $self->{'curr_y_min'} + $self->{'text_space'}; |
3 | 3 | use v5.12; |
4 | 4 | |
5 | 5 | package Chart::BrushStyles; |
6 | our $VERSION = 'v2.403.7'; | |
6 | our $VERSION = 'v2.403.8'; | |
7 | 7 | |
8 | 8 | use Carp; |
9 | 9 | use GD; |
0 | use v5.12; | |
1 | ||
2 | # named colors from X11, HTML (SVG) standard and Pantone report | |
3 | ||
4 | package Chart::Color::Constant; | |
5 | our $VERSION = 'v2.403.7'; | |
6 | use Carp; | |
7 | use Chart::Color::Value; | |
8 | ||
9 | our %rgbhsl_from_name = ( # 2.6 MB | |
10 | # http://en.wikipedia.org/wiki/Web_colors#X11_color_names | |
11 | 'white' => [ 255, 255, 255, 0, 0, 100 ], | |
12 | 'black' => [ 0, 0, 0, 0, 0, 0 ], | |
13 | 'red' => [ 255, 0, 0, 0, 100, 50 ], | |
14 | 'green' => [ 0, 128, 0, 120, 100, 25 ], | |
15 | 'blue' => [ 0, 0, 255, 240, 100, 50 ], | |
16 | 'yellow' => [ 255, 255, 0, 60, 100, 50 ], | |
17 | 'purple' => [ 128, 0, 128, 300, 100, 25 ], | |
18 | 'pink' => [ 255, 192, 203, 350, 100, 88 ], | |
19 | 'peach' => [ 250, 125, 125, 0, 93, 74 ], | |
20 | 'plum' => [ 221, 160, 221, 300, 47, 75 ], | |
21 | 'mauve' => [ 200, 125, 125, 0, 41, 64 ], | |
22 | 'brown' => [ 165, 42, 42, 0, 59, 41 ], | |
23 | 'grey' => [ 225, 225, 225, 0, 0, 88 ], | |
24 | 'aliceblue' => [ 240, 248, 255, 208, 100, 97 ], | |
25 | 'antiquewhite' => [ 250, 235, 215, 34, 78, 91 ], | |
26 | 'antiquewhite1' => [ 255, 239, 219, 33, 100, 93 ], | |
27 | 'antiquewhite2' => [ 238, 223, 204, 34, 50, 87 ], | |
28 | 'antiquewhite3' => [ 205, 192, 176, 33, 22, 75 ], | |
29 | 'antiquewhite4' => [ 139, 131, 120, 35, 8, 51 ], | |
30 | 'aqua' => [ 0, 255, 255, 180, 100, 50 ], | |
31 | 'aquamarine' => [ 127, 255, 212, 160, 100, 75 ], | |
32 | 'aquamarine1' => [ 127, 255, 212, 160, 100, 75 ], | |
33 | 'aquamarine2' => [ 118, 238, 198, 160, 78, 70 ], | |
34 | 'aquamarine3' => [ 102, 205, 170, 160, 51, 60 ], # not in X11 | |
35 | 'aquamarine4' => [ 69, 139, 116, 160, 34, 41 ], | |
36 | 'azure' => [ 240, 255, 255, 180, 100, 97 ], | |
37 | 'azure1' => [ 240, 255, 255, 180, 100, 97 ], | |
38 | 'azure2' => [ 224, 238, 238, 180, 29, 91 ], | |
39 | 'azure3' => [ 193, 205, 205, 180, 11, 78 ], | |
40 | 'azure4' => [ 131, 139, 139, 180, 3, 53 ], | |
41 | 'beige' => [ 245, 245, 220, 60, 56, 91 ], | |
42 | 'bisque' => [ 255, 228, 196, 33, 100, 88 ], | |
43 | 'bisque1' => [ 255, 228, 196, 33, 100, 88 ], | |
44 | 'bisque2' => [ 238, 213, 183, 33, 62, 83 ], | |
45 | 'bisque3' => [ 205, 183, 158, 32, 32, 71 ], | |
46 | 'bisque4' => [ 139, 125, 107, 34, 13, 48 ], | |
47 | 'blanchedalmond' => [ 255, 235, 205, 36, 100, 90 ], | |
48 | 'blue1' => [ 0, 0, 255, 240, 100, 50 ], | |
49 | 'blue2' => [ 0, 0, 238, 240, 100, 47 ], | |
50 | 'blue3' => [ 0, 0, 205, 240, 100, 40 ], | |
51 | 'blue4' => [ 0, 0, 139, 240, 100, 27 ], | |
52 | 'blueviolet' => [ 138, 43, 226, 271, 76, 53 ], | |
53 | 'brown1' => [ 255, 64, 64, 0, 100, 63 ], | |
54 | 'brown2' => [ 238, 59, 59, 0, 84, 58 ], | |
55 | 'brown3' => [ 205, 51, 51, 0, 61, 50 ], | |
56 | 'brown4' => [ 139, 35, 35, 0, 60, 34 ], | |
57 | 'burlywood' => [ 222, 184, 135, 34, 57, 70 ], | |
58 | 'burlywood1' => [ 255, 211, 155, 34, 100, 80 ], | |
59 | 'burlywood2' => [ 238, 197, 145, 34, 73, 75 ], | |
60 | 'burlywood3' => [ 205, 170, 125, 34, 44, 65 ], | |
61 | 'burlywood4' => [ 139, 115, 85, 33, 24, 44 ], | |
62 | 'cadetblue' => [ 95, 158, 160, 182, 25, 50 ], | |
63 | 'cadetblue1' => [ 152, 245, 255, 186, 100, 80 ], | |
64 | 'cadetblue2' => [ 142, 229, 238, 186, 74, 75 ], | |
65 | 'cadetblue3' => [ 122, 197, 205, 186, 45, 64 ], | |
66 | 'cadetblue4' => [ 83, 134, 139, 185, 25, 44 ], | |
67 | 'chartreuse' => [ 127, 255, 0, 90, 100, 50 ], | |
68 | 'chartreuse1' => [ 127, 255, 0, 90, 100, 50 ], | |
69 | 'chartreuse2' => [ 118, 238, 0, 90, 100, 47 ], | |
70 | 'chartreuse3' => [ 102, 205, 0, 90, 100, 40 ], | |
71 | 'chartreuse4' => [ 69, 139, 0, 90, 100, 27 ], | |
72 | 'chocolate' => [ 210, 105, 30, 25, 75, 47 ], | |
73 | 'chocolate1' => [ 255, 127, 36, 25, 100, 57 ], | |
74 | 'chocolate2' => [ 238, 118, 33, 25, 86, 53 ], | |
75 | 'chocolate3' => [ 205, 102, 29, 25, 75, 46 ], | |
76 | 'chocolate4' => [ 139, 69, 19, 25, 76, 31 ], | |
77 | 'coral' => [ 255, 127, 80, 16, 100, 66 ], | |
78 | 'coral1' => [ 255, 114, 86, 10, 100, 67 ], | |
79 | 'coral2' => [ 238, 106, 80, 10, 82, 62 ], | |
80 | 'coral3' => [ 205, 91, 69, 10, 58, 54 ], | |
81 | 'coral4' => [ 139, 62, 47, 10, 49, 36 ], | |
82 | 'cornflowerblue' => [ 100, 149, 237, 219, 79, 66 ], | |
83 | 'cornsilk' => [ 255, 248, 220, 48, 100, 93 ], | |
84 | 'cornsilk1' => [ 255, 248, 220, 48, 100, 93 ], | |
85 | 'cornsilk2' => [ 238, 232, 205, 49, 49, 87 ], | |
86 | 'cornsilk3' => [ 205, 200, 177, 49, 22, 75 ], | |
87 | 'cornsilk4' => [ 139, 136, 120, 51, 8, 51 ], | |
88 | 'crimson' => [ 220, 20, 60, 348, 83, 47 ], | |
89 | 'cyan' => [ 0, 255, 255, 180, 100, 50 ], | |
90 | 'cyan1' => [ 0, 255, 255, 180, 100, 50 ], | |
91 | 'cyan2' => [ 0, 238, 238, 180, 100, 47 ], | |
92 | 'cyan3' => [ 0, 205, 205, 180, 100, 40 ], | |
93 | 'cyan4' => [ 0, 139, 139, 180, 100, 27 ], | |
94 | 'darkblue' => [ 0, 0, 139, 240, 100, 27 ], | |
95 | 'darkcyan' => [ 0, 139, 139, 180, 100, 27 ], | |
96 | 'darkgoldenrod' => [ 184, 134, 11, 43, 89, 38 ], | |
97 | 'darkgoldenrod1' => [ 255, 185, 15, 43, 100, 53 ], | |
98 | 'darkgoldenrod2' => [ 238, 173, 14, 43, 89, 49 ], | |
99 | 'darkgoldenrod3' => [ 205, 149, 12, 43, 89, 43 ], | |
100 | 'darkgoldenrod4' => [ 139, 101, 8, 43, 89, 29 ], | |
101 | 'darkgray' => [ 169, 169, 169, 0, 0, 66 ], | |
102 | 'darkgreen' => [ 0, 100, 0, 120, 100, 20 ], | |
103 | 'darkkhaki' => [ 189, 183, 107, 56, 38, 58 ], | |
104 | 'darkmagenta' => [ 139, 0, 139, 300, 100, 27 ], | |
105 | 'darkolivegreen' => [ 85, 107, 47, 82, 39, 30 ], | |
106 | 'darkolivegreen1' => [ 202, 255, 112, 82, 100, 72 ], | |
107 | 'darkolivegreen2' => [ 188, 238, 104, 82, 80, 67 ], | |
108 | 'darkolivegreen3' => [ 162, 205, 90, 82, 53, 58 ], | |
109 | 'darkolivegreen4' => [ 110, 139, 61, 82, 39, 39 ], | |
110 | 'darkorange' => [ 255, 140, 0, 33, 100, 50 ], | |
111 | 'darkorange1' => [ 255, 127, 0, 30, 100, 50 ], | |
112 | 'darkorange2' => [ 238, 118, 0, 30, 100, 47 ], | |
113 | 'darkorange3' => [ 205, 102, 0, 30, 100, 40 ], | |
114 | 'darkorange4' => [ 139, 69, 0, 30, 100, 27 ], | |
115 | 'darkorchid' => [ 153, 50, 204, 280, 61, 50 ], | |
116 | 'darkorchid1' => [ 191, 62, 255, 280, 100, 62 ], | |
117 | 'darkorchid2' => [ 178, 58, 238, 280, 84, 58 ], | |
118 | 'darkorchid3' => [ 154, 50, 205, 280, 61, 50 ], | |
119 | 'darkorchid4' => [ 104, 34, 139, 280, 61, 34 ], | |
120 | 'darkred' => [ 139, 0, 0, 0, 100, 27 ], | |
121 | 'darksalmon' => [ 233, 150, 122, 15, 72, 70 ], | |
122 | 'darkseagreen' => [ 143, 188, 143, 120, 25, 65 ], | |
123 | 'darkseagreen1' => [ 193, 255, 193, 120, 100, 88 ], | |
124 | 'darkseagreen2' => [ 180, 238, 180, 120, 63, 82 ], | |
125 | 'darkseagreen3' => [ 155, 205, 155, 120, 33, 71 ], | |
126 | 'darkseagreen4' => [ 105, 139, 105, 120, 14, 48 ], | |
127 | 'darkslateblue' => [ 72, 61, 139, 248, 39, 39 ], | |
128 | 'darkslategray' => [ 47, 79, 79, 180, 25, 25 ], | |
129 | 'darkslategray1' => [ 151, 255, 255, 180, 100, 80 ], | |
130 | 'darkslategray2' => [ 141, 238, 238, 180, 74, 74 ], | |
131 | 'darkslategray3' => [ 121, 205, 205, 180, 46, 64 ], | |
132 | 'darkslategray4' => [ 82, 139, 139, 180, 26, 43 ], | |
133 | 'darkturquoise' => [ 0, 206, 209, 181, 100, 41 ], | |
134 | 'darkviolet' => [ 148, 0, 211, 282, 100, 41 ], | |
135 | 'deeppink' => [ 255, 20, 147, 328, 100, 54 ], | |
136 | 'deeppink1' => [ 255, 20, 147, 328, 100, 54 ], | |
137 | 'deeppink2' => [ 238, 18, 137, 328, 87, 50 ], | |
138 | 'deeppink3' => [ 205, 16, 118, 328, 86, 43 ], | |
139 | 'deeppink4' => [ 139, 10, 80, 327, 87, 29 ], | |
140 | 'deepskyblue' => [ 0, 191, 255, 195, 100, 50 ], | |
141 | 'deepskyblue1' => [ 0, 191, 255, 195, 100, 50 ], | |
142 | 'deepskyblue2' => [ 0, 178, 238, 195, 100, 47 ], | |
143 | 'deepskyblue3' => [ 0, 154, 205, 195, 100, 40 ], | |
144 | 'deepskyblue4' => [ 0, 104, 139, 195, 100, 27 ], | |
145 | 'dimgray' => [ 105, 105, 105, 0, 0, 41 ], | |
146 | 'dodgerblue' => [ 30, 144, 255, 210, 100, 56 ], | |
147 | 'dodgerblue1' => [ 30, 144, 255, 210, 100, 56 ], | |
148 | 'dodgerblue2' => [ 28, 134, 238, 210, 86, 52 ], | |
149 | 'dodgerblue3' => [ 24, 116, 205, 210, 79, 45 ], | |
150 | 'dodgerblue4' => [ 16, 78, 139, 210, 79, 30 ], | |
151 | 'firebrick' => [ 178, 34, 34, 0, 68, 42 ], | |
152 | 'firebrick1' => [ 255, 48, 48, 0, 100, 59 ], | |
153 | 'firebrick2' => [ 238, 44, 44, 0, 85, 55 ], | |
154 | 'firebrick3' => [ 205, 38, 38, 0, 69, 48 ], | |
155 | 'firebrick4' => [ 139, 26, 26, 0, 68, 32 ], | |
156 | 'floralwhite' => [ 255, 250, 240, 40, 100, 97 ], | |
157 | 'forestgreen' => [ 34, 139, 34, 120, 61, 34 ], | |
158 | 'fuchsia' => [ 255, 0, 255, 300, 100, 50 ], | |
159 | 'gainsboro' => [ 220, 220, 220, 0, 0, 86 ], | |
160 | 'ghostwhite' => [ 248, 248, 255, 240, 100, 99 ], | |
161 | 'gold' => [ 255, 215, 0, 51, 100, 50 ], | |
162 | 'gold1' => [ 255, 215, 0, 51, 100, 50 ], | |
163 | 'gold2' => [ 238, 201, 0, 51, 100, 47 ], | |
164 | 'gold3' => [ 205, 173, 0, 51, 100, 40 ], | |
165 | 'gold4' => [ 139, 117, 0, 51, 100, 27 ], | |
166 | 'goldenrod' => [ 218, 165, 32, 43, 74, 49 ], | |
167 | 'goldenrod1' => [ 255, 193, 37, 43, 100, 57 ], | |
168 | 'goldenrod2' => [ 238, 180, 34, 43, 86, 53 ], | |
169 | 'goldenrod3' => [ 205, 155, 29, 43, 75, 46 ], | |
170 | 'goldenrod4' => [ 139, 105, 20, 43, 75, 31 ], | |
171 | 'gray' => [ 128, 128, 128, 0, 0, 50 ], | |
172 | 'gray1' => [ 3, 3, 3, 0, 0, 1 ], | |
173 | 'gray2' => [ 5, 5, 5, 0, 0, 2 ], | |
174 | 'gray3' => [ 8, 8, 8, 0, 0, 3 ], | |
175 | 'gray4' => [ 10, 10, 10, 0, 0, 4 ], | |
176 | 'gray5' => [ 13, 13, 13, 0, 0, 5 ], | |
177 | 'gray6' => [ 15, 15, 15, 0, 0, 6 ], | |
178 | 'gray7' => [ 18, 18, 18, 0, 0, 7 ], | |
179 | 'gray8' => [ 20, 20, 20, 0, 0, 8 ], | |
180 | 'gray9' => [ 23, 23, 23, 0, 0, 9 ], | |
181 | 'gray10' => [ 26, 26, 26, 0, 0, 10 ], | |
182 | 'gray11' => [ 28, 28, 28, 0, 0, 11 ], | |
183 | 'gray12' => [ 31, 31, 31, 0, 0, 12 ], | |
184 | 'gray13' => [ 33, 33, 33, 0, 0, 13 ], | |
185 | 'gray14' => [ 36, 36, 36, 0, 0, 14 ], | |
186 | 'gray15' => [ 38, 38, 38, 0, 0, 15 ], | |
187 | 'gray16' => [ 41, 41, 41, 0, 0, 16 ], | |
188 | 'gray17' => [ 43, 43, 43, 0, 0, 17 ], | |
189 | 'gray18' => [ 46, 46, 46, 0, 0, 18 ], | |
190 | 'gray19' => [ 48, 48, 48, 0, 0, 19 ], | |
191 | 'gray20' => [ 51, 51, 51, 0, 0, 20 ], | |
192 | 'gray21' => [ 54, 54, 54, 0, 0, 21 ], | |
193 | 'gray22' => [ 56, 56, 56, 0, 0, 22 ], | |
194 | 'gray23' => [ 59, 59, 59, 0, 0, 23 ], | |
195 | 'gray24' => [ 61, 61, 61, 0, 0, 24 ], | |
196 | 'gray25' => [ 64, 64, 64, 0, 0, 25 ], | |
197 | 'gray26' => [ 66, 66, 66, 0, 0, 26 ], | |
198 | 'gray27' => [ 69, 69, 69, 0, 0, 27 ], | |
199 | 'gray28' => [ 71, 71, 71, 0, 0, 28 ], | |
200 | 'gray29' => [ 74, 74, 74, 0, 0, 29 ], | |
201 | 'gray30' => [ 77, 77, 77, 0, 0, 30 ], | |
202 | 'gray31' => [ 79, 79, 79, 0, 0, 31 ], | |
203 | 'gray32' => [ 82, 82, 82, 0, 0, 32 ], | |
204 | 'gray33' => [ 84, 84, 84, 0, 0, 33 ], | |
205 | 'gray34' => [ 87, 87, 87, 0, 0, 34 ], | |
206 | 'gray35' => [ 89, 89, 89, 0, 0, 35 ], | |
207 | 'gray36' => [ 92, 92, 92, 0, 0, 36 ], | |
208 | 'gray37' => [ 94, 94, 94, 0, 0, 37 ], | |
209 | 'gray38' => [ 97, 97, 97, 0, 0, 38 ], | |
210 | 'gray39' => [ 99, 99, 99, 0, 0, 39 ], | |
211 | 'gray40' => [ 102, 102, 102, 0, 0, 40 ], | |
212 | 'gray41' => [ 105, 105, 105, 0, 0, 41 ], | |
213 | 'gray42' => [ 107, 107, 107, 0, 0, 42 ], | |
214 | 'gray43' => [ 110, 110, 110, 0, 0, 43 ], | |
215 | 'gray44' => [ 112, 112, 112, 0, 0, 44 ], | |
216 | 'gray45' => [ 115, 115, 115, 0, 0, 45 ], | |
217 | 'gray46' => [ 117, 117, 117, 0, 0, 46 ], | |
218 | 'gray47' => [ 120, 120, 120, 0, 0, 47 ], | |
219 | 'gray48' => [ 122, 122, 122, 0, 0, 48 ], | |
220 | 'gray49' => [ 125, 125, 125, 0, 0, 49 ], | |
221 | 'gray50' => [ 127, 127, 127, 0, 0, 50 ], | |
222 | 'gray51' => [ 130, 130, 130, 0, 0, 51 ], | |
223 | 'gray52' => [ 133, 133, 133, 0, 0, 52 ], | |
224 | 'gray53' => [ 135, 135, 135, 0, 0, 53 ], | |
225 | 'gray54' => [ 138, 138, 138, 0, 0, 54 ], | |
226 | 'gray55' => [ 140, 140, 140, 0, 0, 55 ], | |
227 | 'gray56' => [ 143, 143, 143, 0, 0, 56 ], | |
228 | 'gray57' => [ 145, 145, 145, 0, 0, 57 ], | |
229 | 'gray58' => [ 148, 148, 148, 0, 0, 58 ], | |
230 | 'gray59' => [ 150, 150, 150, 0, 0, 59 ], | |
231 | 'gray60' => [ 153, 153, 153, 0, 0, 60 ], | |
232 | 'gray61' => [ 156, 156, 156, 0, 0, 61 ], | |
233 | 'gray62' => [ 158, 158, 158, 0, 0, 62 ], | |
234 | 'gray63' => [ 161, 161, 161, 0, 0, 63 ], | |
235 | 'gray64' => [ 163, 163, 163, 0, 0, 64 ], | |
236 | 'gray65' => [ 166, 166, 166, 0, 0, 65 ], | |
237 | 'gray66' => [ 168, 168, 168, 0, 0, 66 ], | |
238 | 'gray67' => [ 171, 171, 171, 0, 0, 67 ], | |
239 | 'gray68' => [ 173, 173, 173, 0, 0, 68 ], | |
240 | 'gray69' => [ 176, 176, 176, 0, 0, 69 ], | |
241 | 'gray70' => [ 179, 179, 179, 0, 0, 70 ], | |
242 | 'gray71' => [ 181, 181, 181, 0, 0, 71 ], | |
243 | 'gray72' => [ 184, 184, 184, 0, 0, 72 ], | |
244 | 'gray73' => [ 186, 186, 186, 0, 0, 73 ], | |
245 | 'gray74' => [ 189, 189, 189, 0, 0, 74 ], | |
246 | 'gray75' => [ 191, 191, 191, 0, 0, 75 ], | |
247 | 'gray76' => [ 194, 194, 194, 0, 0, 76 ], | |
248 | 'gray77' => [ 196, 196, 196, 0, 0, 77 ], | |
249 | 'gray78' => [ 199, 199, 199, 0, 0, 78 ], | |
250 | 'gray79' => [ 201, 201, 201, 0, 0, 79 ], | |
251 | 'gray80' => [ 204, 204, 204, 0, 0, 80 ], | |
252 | 'gray81' => [ 207, 207, 207, 0, 0, 81 ], | |
253 | 'gray82' => [ 209, 209, 209, 0, 0, 82 ], | |
254 | 'gray83' => [ 212, 212, 212, 0, 0, 83 ], | |
255 | 'gray84' => [ 214, 214, 214, 0, 0, 84 ], | |
256 | 'gray85' => [ 217, 217, 217, 0, 0, 85 ], | |
257 | 'gray86' => [ 219, 219, 219, 0, 0, 86 ], | |
258 | 'gray87' => [ 222, 222, 222, 0, 0, 87 ], | |
259 | 'gray88' => [ 224, 224, 224, 0, 0, 88 ], | |
260 | 'gray89' => [ 227, 227, 227, 0, 0, 89 ], | |
261 | 'gray90' => [ 229, 229, 229, 0, 0, 90 ], | |
262 | 'gray91' => [ 232, 232, 232, 0, 0, 91 ], | |
263 | 'gray92' => [ 235, 235, 235, 0, 0, 92 ], | |
264 | 'gray93' => [ 237, 237, 237, 0, 0, 93 ], | |
265 | 'gray94' => [ 240, 240, 240, 0, 0, 94 ], | |
266 | 'gray95' => [ 242, 242, 242, 0, 0, 95 ], | |
267 | 'gray97' => [ 247, 247, 247, 0, 0, 97 ], | |
268 | 'gray98' => [ 250, 250, 250, 0, 0, 98 ], | |
269 | 'gray99' => [ 252, 252, 252, 0, 0, 99 ], | |
270 | 'green1' => [ 0, 255, 0, 120, 100, 50 ], | |
271 | 'green2' => [ 0, 238, 0, 120, 100, 47 ], | |
272 | 'green3' => [ 0, 205, 0, 120, 100, 40 ], | |
273 | 'green4' => [ 0, 139, 0, 120, 100, 27 ], | |
274 | 'greenyellow' => [ 173, 255, 47, 84, 100, 59 ], | |
275 | 'grey1' => [ 3, 3, 3, 0, 0, 1 ], | |
276 | 'grey2' => [ 5, 5, 5, 0, 0, 2 ], | |
277 | 'grey3' => [ 8, 8, 8, 0, 0, 3 ], | |
278 | 'grey4' => [ 10, 10, 10, 0, 0, 4 ], | |
279 | 'honeydew' => [ 240, 255, 240, 120, 100, 97 ], | |
280 | 'honeydew1' => [ 240, 255, 240, 120, 100, 97 ], | |
281 | 'honeydew2' => [ 224, 238, 224, 120, 29, 91 ], | |
282 | 'honeydew3' => [ 193, 205, 193, 120, 11, 78 ], | |
283 | 'honeydew4' => [ 131, 139, 131, 120, 3, 53 ], | |
284 | 'hotpink' => [ 255, 105, 180, 330, 100, 71 ], | |
285 | 'hotpink1' => [ 255, 110, 180, 331, 100, 72 ], | |
286 | 'hotpink2' => [ 238, 106, 167, 332, 80, 67 ], | |
287 | 'hotpink3' => [ 205, 96, 144, 334, 52, 59 ], | |
288 | 'hotpink4' => [ 139, 58, 98, 330, 41, 39 ], | |
289 | 'indianred' => [ 205, 92, 92, 0, 53, 58 ], | |
290 | 'indianred1' => [ 255, 106, 106, 0, 100, 71 ], | |
291 | 'indianred2' => [ 238, 99, 99, 0, 80, 66 ], | |
292 | 'indianred3' => [ 205, 85, 85, 0, 55, 57 ], | |
293 | 'indianred4' => [ 139, 58, 58, 0, 41, 39 ], | |
294 | 'indigo' => [ 75, 0, 130, 275, 100, 25 ], | |
295 | 'ivory' => [ 255, 255, 240, 60, 100, 97 ], | |
296 | 'ivory1' => [ 255, 255, 240, 60, 100, 97 ], | |
297 | 'ivory2' => [ 238, 238, 224, 60, 29, 91 ], | |
298 | 'ivory3' => [ 205, 205, 193, 60, 11, 78 ], | |
299 | 'ivory4' => [ 139, 139, 131, 60, 3, 53 ], | |
300 | 'khaki' => [ 240, 230, 140, 54, 77, 75 ], | |
301 | 'khaki1' => [ 255, 246, 143, 55, 100, 78 ], | |
302 | 'khaki2' => [ 238, 230, 133, 55, 76, 73 ], | |
303 | 'khaki3' => [ 205, 198, 115, 55, 47, 63 ], | |
304 | 'khaki4' => [ 139, 134, 78, 55, 28, 43 ], | |
305 | 'lavender' => [ 230, 230, 250, 240, 67, 94 ], | |
306 | 'lavenderblush' => [ 255, 240, 245, 340, 100, 97 ], | |
307 | 'lavenderblush1' => [ 255, 240, 245, 340, 100, 97 ], | |
308 | 'lavenderblush2' => [ 238, 224, 229, 339, 29, 91 ], | |
309 | 'lavenderblush3' => [ 205, 193, 197, 340, 11, 78 ], | |
310 | 'lavenderblush4' => [ 139, 131, 134, 338, 3, 53 ], | |
311 | 'lawngreen' => [ 124, 252, 0, 90, 100, 49 ], | |
312 | 'lemonchiffon' => [ 255, 250, 205, 54, 100, 90 ], | |
313 | 'lemonchiffon1' => [ 255, 250, 205, 54, 100, 90 ], | |
314 | 'lemonchiffon2' => [ 238, 233, 191, 54, 58, 84 ], | |
315 | 'lemonchiffon3' => [ 205, 201, 165, 54, 29, 73 ], | |
316 | 'lemonchiffon4' => [ 139, 137, 112, 56, 11, 49 ], | |
317 | 'light' => [ 238, 221, 130, 51, 76, 72 ], | |
318 | 'lightblue' => [ 173, 216, 230, 195, 53, 79 ], | |
319 | 'lightblue1' => [ 191, 239, 255, 195, 100, 87 ], | |
320 | 'lightblue2' => [ 178, 223, 238, 195, 64, 82 ], | |
321 | 'lightblue3' => [ 154, 192, 205, 195, 34, 70 ], | |
322 | 'lightblue4' => [ 104, 131, 139, 194, 14, 48 ], | |
323 | 'lightcoral' => [ 240, 128, 128, 0, 79, 72 ], | |
324 | 'lightcyan' => [ 224, 255, 255, 180, 100, 94 ], | |
325 | 'lightcyan1' => [ 224, 255, 255, 180, 100, 94 ], | |
326 | 'lightcyan2' => [ 209, 238, 238, 180, 46, 88 ], | |
327 | 'lightcyan3' => [ 180, 205, 205, 180, 20, 75 ], | |
328 | 'lightcyan4' => [ 122, 139, 139, 180, 7, 51 ], | |
329 | 'lightgoldenrod' => [ 238, 221, 130, 51, 76, 72 ], | |
330 | 'lightgoldenrod1' => [ 255, 236, 139, 50, 100, 77 ], | |
331 | 'lightgoldenrod2' => [ 238, 220, 130, 50, 76, 72 ], | |
332 | 'lightgoldenrod3' => [ 205, 190, 112, 50, 48, 62 ], | |
333 | 'lightgoldenrod4' => [ 139, 129, 76, 50, 29, 42 ], | |
334 | 'lightgray' => [ 211, 211, 211, 0, 0, 83 ], | |
335 | 'lightgreen' => [ 144, 238, 144, 120, 73, 75 ], | |
336 | 'lightpink' => [ 255, 182, 193, 351, 100, 86 ], | |
337 | 'lightpink1' => [ 255, 174, 185, 352, 100, 84 ], | |
338 | 'lightpink2' => [ 238, 162, 173, 351, 69, 78 ], | |
339 | 'lightpink3' => [ 205, 140, 149, 352, 39, 68 ], | |
340 | 'lightpink4' => [ 139, 95, 101, 352, 19, 46 ], | |
341 | 'lightpurple' => [ 145, 0, 250, 275, 100, 49 ], # not in X11 | |
342 | 'lightsalmon' => [ 255, 160, 122, 17, 100, 74 ], | |
343 | 'lightsalmon1' => [ 255, 160, 122, 17, 100, 74 ], | |
344 | 'lightsalmon2' => [ 238, 149, 114, 17, 78, 69 ], | |
345 | 'lightsalmon3' => [ 205, 129, 98, 17, 52, 59 ], | |
346 | 'lightsalmon4' => [ 139, 87, 66, 17, 36, 40 ], | |
347 | 'lightseagreen' => [ 32, 178, 170, 177, 70, 41 ], | |
348 | 'lightskyblue' => [ 135, 206, 250, 203, 92, 75 ], | |
349 | 'lightskyblue1' => [ 176, 226, 255, 202, 100, 85 ], | |
350 | 'lightskyblue2' => [ 164, 211, 238, 202, 69, 79 ], | |
351 | 'lightskyblue3' => [ 141, 182, 205, 202, 39, 68 ], | |
352 | 'lightskyblue4' => [ 96, 123, 139, 202, 18, 46 ], | |
353 | 'lightslateblue' => [ 132, 112, 255, 248, 100, 72 ], | |
354 | 'lightslategray' => [ 119, 136, 153, 210, 14, 53 ], | |
355 | 'lightsteelblue' => [ 176, 196, 222, 214, 41, 78 ], | |
356 | 'lightsteelblue1' => [ 202, 225, 255, 214, 100, 90 ], | |
357 | 'lightsteelblue2' => [ 188, 210, 238, 214, 60, 84 ], | |
358 | 'lightsteelblue3' => [ 162, 181, 205, 213, 30, 72 ], | |
359 | 'lightsteelblue4' => [ 110, 123, 139, 213, 12, 49 ], | |
360 | 'lightyellow' => [ 255, 255, 224, 60, 100, 94 ], | |
361 | 'lightyellow1' => [ 255, 255, 224, 60, 100, 94 ], | |
362 | 'lightyellow2' => [ 238, 238, 209, 60, 46, 88 ], | |
363 | 'lightyellow3' => [ 205, 205, 180, 60, 20, 75 ], | |
364 | 'lightyellow4' => [ 139, 139, 122, 60, 7, 51 ], | |
365 | 'lime' => [ 0, 255, 0, 120, 100, 50 ], | |
366 | 'limegreen' => [ 50, 205, 50, 120, 61, 50 ], | |
367 | 'linen' => [ 250, 240, 230, 30, 67, 94 ], | |
368 | 'magenta' => [ 255, 0, 255, 300, 100, 50 ], | |
369 | 'magenta1' => [ 255, 0, 255, 300, 100, 50 ], | |
370 | 'magenta2' => [ 238, 0, 238, 300, 100, 47 ], | |
371 | 'magenta3' => [ 205, 0, 205, 300, 100, 40 ], | |
372 | 'magenta4' => [ 139, 0, 139, 300, 100, 27 ], | |
373 | 'maroon' => [ 128, 0, 0, 0, 100, 25 ], | |
374 | 'maroon1' => [ 255, 52, 179, 322, 100, 60 ], | |
375 | 'maroon2' => [ 238, 48, 167, 322, 85, 56 ], | |
376 | 'maroon3' => [ 205, 41, 144, 322, 67, 48 ], | |
377 | 'maroon4' => [ 139, 28, 98, 322, 66, 33 ], | |
378 | 'medium' => [ 102, 205, 170, 160, 51, 60 ], | |
379 | 'mediumaquamarine' => [ 102, 205, 170, 160, 51, 60 ], | |
380 | 'mediumblue' => [ 0, 0, 205, 240, 100, 40 ], | |
381 | 'mediumorchid' => [ 186, 85, 211, 288, 59, 58 ], | |
382 | 'mediumorchid1' => [ 224, 102, 255, 288, 100, 70 ], | |
383 | 'mediumorchid2' => [ 209, 95, 238, 288, 81, 65 ], | |
384 | 'mediumorchid3' => [ 180, 82, 205, 288, 55, 56 ], | |
385 | 'mediumorchid4' => [ 122, 55, 139, 288, 43, 38 ], | |
386 | 'mediumpurple' => [ 147, 112, 219, 260, 60, 65 ], | |
387 | 'mediumpurple1' => [ 171, 130, 255, 260, 100, 75 ], | |
388 | 'mediumpurple2' => [ 159, 121, 238, 259, 77, 70 ], | |
389 | 'mediumpurple3' => [ 137, 104, 205, 260, 50, 61 ], | |
390 | 'mediumpurple4' => [ 93, 71, 139, 259, 32, 41 ], | |
391 | 'mediumseagreen' => [ 60, 179, 113, 147, 50, 47 ], | |
392 | 'mediumslateblue' => [ 123, 104, 238, 249, 80, 67 ], | |
393 | 'mediumspringgreen' => [ 0, 250, 154, 157, 100, 49 ], | |
394 | 'mediumturquoise' => [ 72, 209, 204, 178, 60, 55 ], | |
395 | 'mediumvioletred' => [ 199, 21, 133, 322, 81, 43 ], | |
396 | 'midnightblue' => [ 25, 25, 112, 240, 64, 27 ], | |
397 | 'mintcream' => [ 245, 255, 250, 150, 100, 98 ], | |
398 | 'mistyrose' => [ 255, 228, 225, 6, 100, 94 ], | |
399 | 'mistyrose1' => [ 255, 228, 225, 6, 100, 94 ], | |
400 | 'mistyrose2' => [ 238, 213, 210, 6, 45, 88 ], | |
401 | 'mistyrose3' => [ 205, 183, 181, 5, 19, 76 ], | |
402 | 'mistyrose4' => [ 139, 125, 123, 8, 6, 51 ], | |
403 | 'moccasin' => [ 255, 228, 181, 38, 100, 85 ], | |
404 | 'navajowhite' => [ 255, 222, 173, 36, 100, 84 ], | |
405 | 'navajowhite1' => [ 255, 222, 173, 36, 100, 84 ], | |
406 | 'navajowhite2' => [ 238, 207, 161, 36, 69, 78 ], | |
407 | 'navajowhite3' => [ 205, 179, 139, 36, 40, 67 ], | |
408 | 'navajowhite4' => [ 139, 121, 94, 36, 19, 46 ], | |
409 | 'navy' => [ 0, 0, 128, 240, 100, 25 ], | |
410 | 'navyblue' => [ 0, 0, 128, 240, 100, 25 ], | |
411 | 'oldlace' => [ 253, 245, 230, 39, 85, 95 ], | |
412 | 'olive' => [ 128, 128, 0, 60, 100, 25 ], | |
413 | 'olivedrab' => [ 107, 142, 35, 80, 60, 35 ], | |
414 | 'olivedrab1' => [ 192, 255, 62, 80, 100, 62 ], | |
415 | 'olivedrab2' => [ 179, 238, 58, 80, 84, 58 ], | |
416 | 'olivedrab3' => [ 154, 205, 50, 80, 61, 50 ], | |
417 | 'olivedrab4' => [ 105, 139, 34, 79, 61, 34 ], | |
418 | 'orange' => [ 255, 165, 0, 39, 100, 50 ], | |
419 | 'orange1' => [ 255, 165, 0, 39, 100, 50 ], | |
420 | 'orange2' => [ 238, 154, 0, 39, 100, 47 ], | |
421 | 'orange3' => [ 205, 133, 0, 39, 100, 40 ], | |
422 | 'orange4' => [ 139, 90, 0, 39, 100, 27 ], | |
423 | 'orangered' => [ 255, 69, 0, 16, 100, 50 ], | |
424 | 'orangered1' => [ 255, 69, 0, 16, 100, 50 ], | |
425 | 'orangered2' => [ 238, 64, 0, 16, 100, 47 ], | |
426 | 'orangered3' => [ 205, 55, 0, 16, 100, 40 ], | |
427 | 'orangered4' => [ 139, 37, 0, 16, 100, 27 ], | |
428 | 'orchid' => [ 218, 112, 214, 302, 59, 65 ], | |
429 | 'orchid1' => [ 255, 131, 250, 302, 100, 76 ], | |
430 | 'orchid2' => [ 238, 122, 233, 303, 77, 71 ], | |
431 | 'orchid3' => [ 205, 105, 201, 302, 50, 61 ], | |
432 | 'orchid4' => [ 139, 71, 137, 302, 32, 41 ], | |
433 | 'pale' => [ 219, 112, 147, 340, 60, 65 ], | |
434 | 'palegoldenrod' => [ 238, 232, 170, 55, 67, 80 ], | |
435 | 'palegreen' => [ 152, 251, 152, 120, 93, 79 ], | |
436 | 'palegreen1' => [ 154, 255, 154, 120, 100, 80 ], | |
437 | 'palegreen2' => [ 144, 238, 144, 120, 73, 75 ], | |
438 | 'palegreen3' => [ 124, 205, 124, 120, 45, 65 ], | |
439 | 'palegreen4' => [ 84, 139, 84, 120, 25, 44 ], | |
440 | 'paleturquoise' => [ 175, 238, 238, 180, 65, 81 ], | |
441 | 'paleturquoise1' => [ 187, 255, 255, 180, 100, 87 ], | |
442 | 'paleturquoise2' => [ 174, 238, 238, 180, 65, 81 ], | |
443 | 'paleturquoise3' => [ 150, 205, 205, 180, 35, 70 ], | |
444 | 'paleturquoise4' => [ 102, 139, 139, 180, 15, 47 ], | |
445 | 'palevioletred' => [ 219, 112, 147, 340, 60, 65 ], | |
446 | 'palevioletred1' => [ 255, 130, 171, 340, 100, 75 ], | |
447 | 'palevioletred2' => [ 238, 121, 159, 341, 77, 70 ], | |
448 | 'palevioletred3' => [ 205, 104, 137, 340, 50, 61 ], | |
449 | 'palevioletred4' => [ 139, 71, 93, 341, 32, 41 ], | |
450 | 'papayawhip' => [ 255, 239, 213, 37, 100, 92 ], | |
451 | 'peachpuff' => [ 255, 218, 185, 28, 100, 86 ], | |
452 | 'peachpuff1' => [ 255, 218, 185, 28, 100, 86 ], | |
453 | 'peachpuff2' => [ 238, 203, 173, 28, 66, 81 ], | |
454 | 'peachpuff3' => [ 205, 175, 149, 28, 36, 69 ], | |
455 | 'peachpuff4' => [ 139, 119, 101, 28, 16, 47 ], | |
456 | 'peru' => [ 205, 133, 63, 30, 59, 53 ], | |
457 | 'pink1' => [ 255, 181, 197, 347, 100, 85 ], | |
458 | 'pink2' => [ 238, 169, 184, 347, 67, 80 ], | |
459 | 'pink3' => [ 205, 145, 158, 347, 38, 69 ], | |
460 | 'pink4' => [ 139, 99, 108, 347, 17, 47 ], | |
461 | 'plum1' => [ 255, 187, 255, 300, 100, 87 ], | |
462 | 'plum2' => [ 238, 174, 238, 300, 65, 81 ], | |
463 | 'plum3' => [ 205, 150, 205, 300, 35, 70 ], | |
464 | 'plum4' => [ 139, 102, 139, 300, 15, 47 ], | |
465 | 'powderblue' => [ 176, 224, 230, 187, 52, 80 ], | |
466 | 'purple1' => [ 155, 48, 255, 271, 100, 59 ], | |
467 | 'purple2' => [ 145, 44, 238, 271, 85, 55 ], | |
468 | 'purple3' => [ 125, 38, 205, 271, 69, 48 ], | |
469 | 'purple4' => [ 85, 26, 139, 271, 68, 32 ], | |
470 | 'rebeccapurple' => [ 102, 51, 153, 270, 50, 40 ], | |
471 | 'red1' => [ 255, 0, 0, 0, 100, 50 ], | |
472 | 'red2' => [ 238, 0, 0, 0, 100, 47 ], | |
473 | 'red3' => [ 205, 0, 0, 0, 100, 40 ], | |
474 | 'red4' => [ 139, 0, 0, 0, 100, 27 ], | |
475 | 'rosybrown' => [ 188, 143, 143, 0, 25, 65 ], | |
476 | 'rosybrown1' => [ 255, 193, 193, 0, 100, 88 ], | |
477 | 'rosybrown2' => [ 238, 180, 180, 0, 63, 82 ], | |
478 | 'rosybrown3' => [ 205, 155, 155, 0, 33, 71 ], | |
479 | 'rosybrown4' => [ 139, 105, 105, 0, 14, 48 ], | |
480 | 'royalblue' => [ 65, 105, 225, 225, 73, 57 ], | |
481 | 'royalblue1' => [ 72, 118, 255, 225, 100, 64 ], | |
482 | 'royalblue2' => [ 67, 110, 238, 225, 83, 60 ], | |
483 | 'royalblue3' => [ 58, 95, 205, 225, 60, 52 ], | |
484 | 'royalblue4' => [ 39, 64, 139, 225, 56, 35 ], | |
485 | 'saddlebrown' => [ 139, 69, 19, 25, 76, 31 ], | |
486 | 'salmon' => [ 250, 128, 114, 6, 93, 71 ], | |
487 | 'salmon1' => [ 255, 140, 105, 14, 100, 71 ], | |
488 | 'salmon2' => [ 238, 130, 98, 14, 80, 66 ], | |
489 | 'salmon3' => [ 205, 112, 84, 14, 55, 57 ], | |
490 | 'salmon4' => [ 139, 76, 57, 14, 42, 38 ], | |
491 | 'sandybrown' => [ 244, 164, 96, 28, 87, 67 ], | |
492 | 'seagreen' => [ 46, 139, 87, 146, 50, 36 ], | |
493 | 'seagreen1' => [ 84, 255, 159, 146, 100, 66 ], | |
494 | 'seagreen2' => [ 78, 238, 148, 146, 82, 62 ], | |
495 | 'seagreen3' => [ 67, 205, 128, 147, 58, 53 ], | |
496 | 'seagreen4' => [ 46, 139, 87, 146, 50, 36 ], | |
497 | 'seashell' => [ 255, 245, 238, 25, 100, 97 ], | |
498 | 'seashell1' => [ 255, 245, 238, 25, 100, 97 ], | |
499 | 'seashell2' => [ 238, 229, 222, 26, 32, 90 ], | |
500 | 'seashell3' => [ 205, 197, 191, 26, 12, 78 ], | |
501 | 'seashell4' => [ 139, 134, 130, 27, 4, 53 ], | |
502 | 'sienna' => [ 160, 82, 45, 19, 56, 40 ], | |
503 | 'sienna1' => [ 255, 130, 71, 19, 100, 64 ], | |
504 | 'sienna2' => [ 238, 121, 66, 19, 83, 60 ], | |
505 | 'sienna3' => [ 205, 104, 57, 19, 60, 51 ], | |
506 | 'sienna4' => [ 139, 71, 38, 20, 57, 35 ], | |
507 | 'silver' => [ 192, 192, 192, 0, 0, 75 ], | |
508 | 'skyblue' => [ 135, 206, 235, 197, 71, 73 ], | |
509 | 'skyblue1' => [ 135, 206, 255, 205, 100, 76 ], | |
510 | 'skyblue2' => [ 126, 192, 238, 205, 77, 71 ], | |
511 | 'skyblue3' => [ 108, 166, 205, 204, 49, 61 ], | |
512 | 'skyblue4' => [ 74, 112, 139, 205, 31, 42 ], | |
513 | 'slateblue' => [ 106, 90, 205, 248, 53, 58 ], | |
514 | 'slateblue1' => [ 131, 111, 255, 248, 100, 72 ], | |
515 | 'slateblue2' => [ 122, 103, 238, 248, 80, 67 ], | |
516 | 'slateblue3' => [ 105, 89, 205, 248, 54, 58 ], | |
517 | 'slateblue4' => [ 71, 60, 139, 248, 40, 39 ], | |
518 | 'slategray' => [ 112, 128, 144, 210, 13, 50 ], | |
519 | 'slategray1' => [ 198, 226, 255, 211, 100, 89 ], | |
520 | 'slategray2' => [ 185, 211, 238, 211, 61, 83 ], | |
521 | 'slategray3' => [ 159, 182, 205, 210, 32, 71 ], | |
522 | 'slategray4' => [ 108, 123, 139, 211, 13, 48 ], | |
523 | 'snow' => [ 255, 250, 250, 0, 100, 99 ], | |
524 | 'snow1' => [ 255, 250, 250, 0, 100, 99 ], | |
525 | 'snow2' => [ 238, 233, 233, 0, 13, 92 ], | |
526 | 'snow3' => [ 205, 201, 201, 0, 4, 80 ], | |
527 | 'snow4' => [ 139, 137, 137, 0, 1, 54 ], | |
528 | 'springgreen' => [ 0, 255, 127, 150, 100, 50 ], | |
529 | 'springgreen1' => [ 0, 255, 127, 150, 100, 50 ], | |
530 | 'springgreen2' => [ 0, 238, 118, 150, 100, 47 ], | |
531 | 'springgreen3' => [ 0, 205, 102, 150, 100, 40 ], | |
532 | 'springgreen4' => [ 0, 139, 69, 150, 100, 27 ], | |
533 | 'steelblue' => [ 70, 130, 180, 207, 44, 49 ], | |
534 | 'steelblue1' => [ 99, 184, 255, 207, 100, 69 ], | |
535 | 'steelblue2' => [ 92, 172, 238, 207, 81, 65 ], | |
536 | 'steelblue3' => [ 79, 148, 205, 207, 56, 56 ], | |
537 | 'steelblue4' => [ 54, 100, 139, 208, 44, 38 ], | |
538 | 'tan' => [ 210, 180, 140, 34, 44, 69 ], | |
539 | 'tan1' => [ 255, 165, 79, 29, 100, 65 ], | |
540 | 'tan2' => [ 238, 154, 73, 29, 83, 61 ], | |
541 | 'tan3' => [ 205, 133, 63, 30, 59, 53 ], | |
542 | 'tan4' => [ 139, 90, 43, 29, 53, 36 ], | |
543 | 'teal' => [ 0, 128, 128, 180, 100, 25 ], | |
544 | 'thistle' => [ 216, 191, 216, 300, 24, 80 ], | |
545 | 'thistle1' => [ 255, 225, 255, 300, 100, 94 ], | |
546 | 'thistle2' => [ 238, 210, 238, 300, 45, 88 ], | |
547 | 'thistle3' => [ 205, 181, 205, 300, 19, 76 ], | |
548 | 'thistle4' => [ 139, 123, 139, 300, 6, 51 ], | |
549 | 'tomato' => [ 255, 99, 71, 9, 100, 64 ], | |
550 | 'tomato1' => [ 255, 99, 71, 9, 100, 64 ], | |
551 | 'tomato2' => [ 238, 92, 66, 9, 83, 60 ], | |
552 | 'tomato3' => [ 205, 79, 57, 9, 60, 51 ], | |
553 | 'tomato4' => [ 139, 54, 38, 10, 57, 35 ], | |
554 | 'turquoise' => [ 69, 184, 172, 174, 45, 50 ], | |
555 | 'turquoise1' => [ 0, 245, 255, 182, 100, 50 ], | |
556 | 'turquoise2' => [ 0, 229, 238, 182, 100, 47 ], | |
557 | 'turquoise3' => [ 0, 197, 205, 182, 100, 40 ], | |
558 | 'turquoise4' => [ 0, 134, 139, 182, 100, 27 ], | |
559 | 'violet' => [ 238, 130, 238, 300, 76, 72 ], | |
560 | 'violetred' => [ 208, 32, 144, 322, 73, 47 ], | |
561 | 'violetred1' => [ 255, 62, 150, 333, 100, 62 ], | |
562 | 'violetred2' => [ 238, 58, 140, 333, 84, 58 ], | |
563 | 'violetred3' => [ 205, 50, 120, 333, 61, 50 ], | |
564 | 'violetred4' => [ 139, 34, 82, 333, 61, 34 ], | |
565 | 'wheat' => [ 245, 222, 179, 39, 77, 83 ], | |
566 | 'wheat1' => [ 255, 231, 186, 39, 100, 86 ], | |
567 | 'wheat2' => [ 238, 216, 174, 39, 65, 81 ], | |
568 | 'wheat3' => [ 205, 186, 150, 39, 35, 70 ], | |
569 | 'wheat4' => [ 139, 126, 102, 39, 15, 47 ], | |
570 | 'whitesmoke' => [ 245, 245, 245, 0, 0, 96 ], | |
571 | 'yellow1' => [ 255, 255, 0, 60, 100, 50 ], | |
572 | 'yellow2' => [ 238, 238, 0, 60, 100, 47 ], | |
573 | 'yellow3' => [ 205, 205, 0, 60, 100, 40 ], | |
574 | 'yellow4' => [ 139, 139, 0, 60, 100, 27 ], | |
575 | 'yellowgreen' => [ 154, 205, 50, 80, 61, 50 ], | |
576 | # https://www.w3schools.com/colors/colors_trends.asp | |
577 | 'marsala' => [ 149, 82, 81, 1, 30, 45 ], # best 2015-2000 | |
578 | 'radiandorchid' => [ 181, 101, 167, 311, 35, 55 ], | |
579 | 'emerald' => [ 0, 155, 119, 166, 100, 30 ], | |
580 | 'tangerinetango' => [ 221, 65, 36, 9, 73, 50 ], | |
581 | 'honeysucle' => [ 214, 80, 118, 343, 62, 58 ], | |
582 | 'turquoise' => [ 69, 184, 172, 174, 45, 50 ], | |
583 | 'mimosa' => [ 239, 192, 80, 42, 83, 63 ], | |
584 | 'blueizis' => [ 91, 94, 166, 238, 30, 50 ], | |
585 | 'chilipepper' => [ 155, 27, 48, 350, 70, 36 ], | |
586 | 'sanddollar' => [ 223, 207, 190, 31, 34, 81 ], | |
587 | 'blueturquoise' => [ 85, 180, 176, 177, 39, 52 ], | |
588 | 'tigerlily' => [ 225, 93, 68, 10, 72, 57 ], | |
589 | 'aquasky' => [ 127, 205, 205, 180, 44, 65 ], | |
590 | 'truered' => [ 188, 36, 60, 351, 68, 44 ], | |
591 | 'fuchsiarose' => [ 195, 68, 122, 334, 51, 52 ], | |
592 | 'ceruleanblue' => [ 152, 180, 212, 212, 41, 71 ], | |
593 | 'rosequartz' => [ 247, 202, 201, 1, 74, 88 ], # 2016 Spring | |
594 | 'peachecho' => [ 247, 120, 107, 6, 90, 69 ], | |
595 | 'serenity' => [ 145, 168, 208, 218, 40, 69 ], | |
596 | 'snorkelblue' => [ 3, 79, 132, 205, 96, 26 ], | |
597 | 'limpetshell' => [ 152, 221, 222, 181, 51, 73 ], | |
598 | 'lilacgrey' => [ 152, 221, 222, 181, 51, 73 ], | |
599 | 'icedcoffee' => [ 177, 143, 106, 31, 31, 55 ], | |
600 | 'fiesta' => [ 221, 65, 50, 5, 72, 53 ], | |
601 | 'buttercup' => [ 221, 65, 50, 5, 72, 53 ], | |
602 | 'greenflash' => [ 250, 224, 60, 52, 95, 61 ], | |
603 | 'riverside' => [ 76, 106, 146, 214, 32, 44 ], # Fall | |
604 | 'airyblue' => [ 146, 182, 213, 208, 44, 70 ], | |
605 | 'sharkskin' => [ 131, 132, 135, 225, 2, 52 ], | |
606 | 'aurorared' => [ 185, 58, 50, 4, 57, 46 ], | |
607 | 'warmtaupe' => [ 175, 148, 131, 23, 22, 60 ], | |
608 | 'dustycedar' => [ 173, 93, 93, 0, 33, 52 ], | |
609 | 'lushmeadow' => [ 0, 110, 81, 164, 100, 22 ], | |
610 | 'spicymustard' => [ 216, 174, 71, 43, 65, 56 ], | |
611 | 'pottersclay' => [ 158, 70, 36, 17, 63, 38 ], # Potter's Clay | |
612 | 'bodacious' => [ 183, 107, 163, 316, 35, 57 ], | |
613 | 'greenery' => [ 146, 181, 88, 83, 39, 53 ], # 2017 | |
614 | 'niagara' => [ 87, 140, 169, 201, 32, 50 ], | |
615 | 'primroseyellow' => [ 246, 209, 85, 46, 90, 65 ], | |
616 | 'lapisblue' => [ 0, 75, 141, 208, 100, 28 ], | |
617 | 'flame' => [ 242, 85, 44, 12, 88, 56 ], | |
618 | 'islandparadise' => [ 149, 222, 227, 184, 58, 74 ], | |
619 | 'paledogwood' => [ 237, 205, 194, 15, 54, 85 ], | |
620 | 'pinkyarrow' => [ 206, 49, 117, 334, 62, 50 ], | |
621 | 'kale' => [ 90, 114, 71, 93, 23, 36 ], | |
622 | 'hazelnut' => [ 207, 176, 149, 28, 38, 70 ], | |
623 | 'grenadine' => [ 220, 76, 70, 2, 68, 57 ], | |
624 | 'balletslipper' => [ 243, 214, 228, 331, 55, 90 ], | |
625 | 'butterum' => [ 196, 143, 101, 27, 45, 58 ], | |
626 | 'navypeony' => [ 34, 58, 94, 216, 47, 25 ], | |
627 | 'neutralgray' => [ 137, 142, 140, 156, 2, 55 ], | |
628 | 'shadedspruce' => [ 0, 89, 96, 184, 100, 19 ], | |
629 | 'goldenlime' => [ 156, 154, 64, 59, 42, 43 ], | |
630 | 'marina' => [ 79, 132, 196, 213, 50, 54 ], | |
631 | 'autumnmaple' => [ 210, 105, 30, 25, 75, 47 ], | |
632 | 'meadowlark' => [ 236, 219, 84, 53, 80, 63 ], # 2018 | |
633 | 'cherrytomato' => [ 233, 75, 60, 5, 80, 57 ], | |
634 | 'littleboyblue' => [ 111, 159, 216, 213, 57, 64 ], | |
635 | 'chilioil' => [ 148, 71, 67, 3, 38, 42 ], | |
636 | 'pinklavender' => [ 219, 177, 205, 320, 37, 78 ], | |
637 | 'bloomingdahlia' => [ 236, 151, 135, 10, 73, 73 ], | |
638 | 'arcadia' => [ 0, 165, 145, 173, 100, 32 ], | |
639 | 'ultraviolet' => [ 107, 91, 149, 257, 24, 47 ], | |
640 | 'emperador' => [ 108, 79, 61, 23, 28, 33 ], | |
641 | 'almostmauve' => [ 234, 222, 219, 12, 26, 89 ], | |
642 | 'springcrocus' => [ 188, 112, 164, 319, 36, 59 ], | |
643 | 'sailorblue' => [ 46, 74, 98, 208, 36, 28 ], | |
644 | 'harbormist' => [ 180, 183, 186, 210, 4, 72 ], | |
645 | 'warmsand' => [ 192, 171, 142, 35, 28, 65 ], | |
646 | 'coconutmilk' => [ 240, 237, 229, 44, 27, 92 ], | |
647 | 'redpear' => [ 127, 65, 69, 356, 32, 38 ], | |
648 | 'valiantpoppy' => [ 189, 61, 58, 1, 53, 48 ], | |
649 | 'nebulasblue' => [ 63, 105, 170, 216, 46, 46 ], | |
650 | 'ceylonyellow' => [ 213, 174, 65, 44, 64, 55 ], | |
651 | 'martiniolive' => [ 118, 111, 87, 46, 15, 40 ], | |
652 | 'russetorange' => [ 228, 122, 46, 25, 77, 54 ], | |
653 | 'crocuspetal' => [ 190, 158, 201, 285, 28, 70 ], | |
654 | 'limelight' => [ 241, 234, 127, 56, 80, 72 ], | |
655 | 'quetzalgreen' => [ 0, 110, 109, 179, 100, 22 ], | |
656 | 'sargassosea' => [ 72, 81, 103, 223, 18, 34 ], | |
657 | 'tofu' => [ 234, 230, 218, 45, 28, 89 ], | |
658 | 'almondbuff' => [ 209, 184, 148, 35, 40, 70 ], | |
659 | 'quietgray' => [ 188, 188, 190, 240, 2, 74 ], | |
660 | 'meerkat' => [ 169, 117, 79, 25, 36, 49 ], | |
661 | 'fiesta' => [ 221, 65, 50, 5, 72, 53 ], # 2019 | |
662 | 'jesterred' => [ 158, 16, 48, 346, 82, 34 ], | |
663 | 'turmeric' => [ 254, 132, 14, 30, 99, 53 ], | |
664 | 'livingcoral' => [ 255, 111, 97, 5, 100, 69 ], | |
665 | 'pinkpeacock' => [ 198, 33, 104, 334, 71, 45 ], | |
666 | 'pepperstem' => [ 141, 148, 64, 65, 40, 42 ], | |
667 | 'aspengold' => [ 255, 214, 98, 44, 100, 69 ], | |
668 | 'princessblue' => [ 0, 83, 156, 208, 100, 31 ], | |
669 | 'toffee' => [ 117, 81, 57, 24, 34, 34 ], | |
670 | 'mangomojito' => [ 214, 156, 47, 39, 67, 51 ], | |
671 | 'terrariummoss' => [ 97, 98, 71, 62, 16, 33 ], | |
672 | 'sweetlilac' => [ 232, 181, 206, 331, 53, 81 ], | |
673 | 'soybean' => [ 210, 194, 157, 42, 37, 72 ], | |
674 | 'eclipse' => [ 52, 49, 72, 248, 19, 24 ], | |
675 | 'sweetcorn' => [ 240, 234, 214, 46, 46, 89 ], | |
676 | 'browngranite' => [ 97, 85, 80, 18, 10, 35 ], | |
677 | 'chilipepper' => [ 155, 27, 48, 350, 70, 36 ], | |
678 | 'bikingred' => [ 119, 33, 46, 351, 57, 30 ], | |
679 | 'peachpink' => [ 250, 154, 133, 11, 92, 75 ], | |
680 | 'rockyroad' => [ 90, 62, 54, 13, 25, 28 ], | |
681 | 'fruitdove' => [ 206, 91, 120, 345, 54, 58 ], | |
682 | 'sugaralmond' => [ 147, 85, 41, 25, 56, 37 ], | |
683 | 'darkcheddar' => [ 224, 129, 25, 31, 80, 49 ], | |
684 | 'galaxyblue' => [ 42, 75, 124, 216, 49, 33 ], | |
685 | 'bluestone' => [ 87, 114, 132, 204, 21, 43 ], | |
686 | 'orangetiger' => [ 249, 103, 20, 22, 95, 53 ], | |
687 | 'eden' => [ 38, 78, 54, 144, 34, 23 ], | |
688 | 'vanillacustard' => [ 243, 224, 190, 38, 69, 85 ], | |
689 | 'eveningblue' => [ 42, 41, 62, 243, 20, 20 ], | |
690 | 'paloma' => [ 159, 156, 153, 30, 3, 61 ], | |
691 | 'guacamole' => [ 121, 123, 58, 62, 36, 35 ], | |
692 | 'flamescarlet' => [ 205, 33, 42, 357, 72, 47 ], # 2020 | |
693 | 'saffron' => [ 255, 165, 0, 39, 100, 50 ], | |
694 | 'biscaygreen' => [ 86, 198, 169, 164, 50, 56 ], | |
695 | 'chive' => [ 75, 83, 53, 76, 22, 27 ], | |
696 | 'fadeddenim' => [ 121, 142, 164, 211, 19, 56 ], | |
697 | 'orangepeel' => [ 250, 122, 53, 21, 95, 59 ], | |
698 | 'mosaicblue' => [ 0, 117, 143, 191, 100, 28 ], | |
699 | 'sunlight' => [ 237, 213, 158, 42, 69, 77 ], | |
700 | 'coralpink' => [ 232, 167, 152, 11, 63, 75 ], | |
701 | 'grapecompote' => [ 107, 88, 118, 278, 15, 40 ], | |
702 | 'lark' => [ 184, 155, 114, 35, 33, 58 ], | |
703 | 'navyblazer' => [ 40, 45, 60, 225, 20, 20 ], | |
704 | 'brilliantwhite' => [ 237, 241, 255, 227, 100, 96 ], | |
705 | 'ash' => [ 160, 153, 152, 8, 4, 61 ], | |
706 | 'amberglow' => [ 220, 121, 62, 22, 69, 55 ], | |
707 | 'samba' => [ 162, 36, 47, 355, 64, 39 ], | |
708 | 'sandstone' => [ 196, 138, 105, 22, 44, 59 ], | |
709 | 'classicblue' => [ 52, 86, 139, 217, 46, 37 ], | |
710 | 'greensheen' => [ 217, 206, 82, 55, 64, 59 ], | |
711 | 'rosetan' => [ 209, 156, 151, 5, 39, 71 ], | |
712 | 'ultramarinegreen' => [ 0, 107, 84, 167, 100, 21 ], | |
713 | 'firedbrick' => [ 106, 46, 42, 4, 43, 29 ], | |
714 | 'peachnougat' => [ 230, 175, 145, 21, 63, 74 ], | |
715 | 'magentapurple' => [ 108, 36, 76, 327, 50, 28 ], | |
716 | 'marigold' => [ 253, 172, 83, 31, 98, 66 ], # 2021 | |
717 | 'cerulean' => [ 155, 183, 212, 211, 40, 72 ], | |
718 | 'rust' => [ 181, 90, 48, 19, 58, 45 ], | |
719 | 'illuminating' => [ 245, 223, 77, 52, 89, 63 ], | |
720 | 'frenchblue' => [ 0, 114, 181, 202, 100, 35 ], | |
721 | 'greenash' => [ 160, 218, 169, 129, 44, 74 ], | |
722 | 'burntcoral' => [ 233, 137, 126, 6, 71, 70 ], | |
723 | 'mint' => [ 0, 161, 112, 162, 100, 32 ], | |
724 | 'amethystorchid' => [ 146, 106, 166, 280, 25, 53 ], | |
725 | 'raspberrysorbet' => [ 210, 56, 108, 340, 63, 52 ], | |
726 | 'inkwell' => [ 54, 57, 69, 228, 12, 24 ], | |
727 | 'ultimategray' => [ 147, 149, 151, 210, 2, 58 ], | |
728 | 'buttercream' => [ 239, 225, 206, 35, 51, 87 ], | |
729 | 'desertmist' => [ 224, 181, 137, 30, 58, 71 ], | |
730 | 'willow' => [ 154, 139, 79, 48, 32, 46 ], | |
731 | ); | |
732 | ||
733 | our (@name_from_rgb, @name_from_hsl); # fill them through: | |
734 | ||
735 | _add_color_to_reverse_search( $_, @{$rgbhsl_from_name{$_}} ) for all_names(); | |
736 | ||
737 | ||
738 | sub all_names { sort keys %rgbhsl_from_name } | |
739 | sub name_taken { exists $rgbhsl_from_name{ _clean_name($_[0]) }} | |
740 | ||
741 | sub rgb_from_name { | |
742 | my $name = _clean_name(shift); | |
743 | @{$rgbhsl_from_name{$name}}[0..2] if name_taken( $name ); | |
744 | } | |
745 | ||
746 | sub hsl_from_name { | |
747 | my $name = _clean_name(shift); | |
748 | @{$rgbhsl_from_name{$name}}[3..5] if name_taken( $name ); | |
749 | } | |
750 | ||
751 | sub name_from_rgb { | |
752 | my (@rgb) = @_; | |
753 | @rgb = @{$rgb[0]} if (ref $rgb[0] eq 'ARRAY'); | |
754 | Chart::Color::Value::check_rgb( @rgb ) and return; # return if sub did carp | |
755 | my @names = _names_from_rgb( @rgb ); | |
756 | wantarray ? @names : $names[0]; | |
757 | } | |
758 | ||
759 | sub name_from_hsl { | |
760 | my (@hsl) = @_; | |
761 | @hsl = @{$hsl[0]} if (ref $hsl[0] eq 'ARRAY'); | |
762 | Chart::Color::Value::check_hsl( @hsl ) and return; | |
763 | my @names = _names_from_hsl( @hsl ); | |
764 | wantarray ? @names : $names[0]; | |
765 | } | |
766 | ||
767 | sub names_in_hsl_range { # @center, (@d | $d) --> @names | |
768 | my $help = 'need two arguments: 1. array with h s l values '. | |
769 | '2. radius (real number) or array with tolerances in h s l direction'; | |
770 | return carp $help if @_ != 2; | |
771 | my ($hsl_center, $radius) = @_; | |
772 | return carp 'first argument has to be an array ref with thre number ([$h, $s, $l])' | |
773 | if ref $hsl_center ne 'ARRAY' or @$hsl_center != 3; | |
774 | return carp 'second argument has to be a integer < 180 or array ref with 3 integer' | |
775 | unless (ref $radius eq 'ARRAY' and @$radius == 3) or (defined $radius and not ref $radius); | |
776 | Chart::Color::Value::check_hsl( @$hsl_center ) and return; | |
777 | ||
778 | my @hsl_delta = ref $radius ? @$radius : ($radius, $radius, $radius); | |
779 | $hsl_delta[$_] = int abs $hsl_delta[$_] for 0 ..2; | |
780 | $hsl_delta[0] = 180 if $hsl_delta[0] > 180; # enough to search complete HSL space (prevent double results) | |
781 | ||
782 | my (@min, @max, @names, $minhrange, $maxhrange); | |
783 | $min[$_] = $hsl_center->[$_] - $hsl_delta[$_] for 0..2; | |
784 | $max[$_] = $hsl_center->[$_] + $hsl_delta[$_] for 0..2; | |
785 | $min[1] = 0 if $min[1] < 0; | |
786 | $min[2] = 0 if $min[2] < 0; | |
787 | $max[1] = 100 if $max[1] > 100; | |
788 | $max[2] = 100 if $max[2] > 100; | |
789 | my @hrange = ($min[0] < 0 ? 0 : $min[0]) .. ($max[0] > 359 ? 359 : $max[0]); | |
790 | push @hrange, (360 + $min[0]) .. 359 if $min[0] < 0; | |
791 | push @hrange, 0 .. ($max[0] - 360) if $max[0] > 359; | |
792 | for my $h (@hrange){ | |
793 | next unless defined $name_from_hsl[ $h ]; | |
794 | for my $s ($min[1] .. $max[1]){ | |
795 | next unless defined $name_from_hsl[ $h ][ $s ]; | |
796 | for my $l ($min[2] .. $max[2]){ | |
797 | my $name = $name_from_hsl[ $h ][ $s ][ $l ]; | |
798 | next unless defined $name; | |
799 | push @names, (ref $name ? $name->[0] : $name); | |
800 | } | |
801 | } | |
802 | } | |
803 | @names = grep {Chart::Color::Value::distance_hsl( $hsl_center ,[hsl_from_name($_)] ) <= $radius} @names if not ref $radius; | |
804 | @names; | |
805 | } | |
806 | ||
807 | sub add_rgb { | |
808 | my ($name, @rgb) = @_; | |
809 | @rgb = @{$rgb[0]} if (ref $rgb[0] eq 'ARRAY'); | |
810 | return carp "missing first argument: color name" unless defined $name and $name; | |
811 | Chart::Color::Value::check_rgb( @rgb ) and return; | |
812 | _add_color( $name, @rgb, Chart::Color::Value::hsl_from_rgb( @rgb ) ); | |
813 | } | |
814 | ||
815 | sub add_hsl { | |
816 | my ($name, @hsl) = @_; | |
817 | @hsl = @{$hsl[0]} if (ref $hsl[0] eq 'ARRAY'); | |
818 | return carp "missing first argument: color name" unless defined $name and $name; | |
819 | Chart::Color::Value::check_hsl( @hsl ) and return; | |
820 | _add_color( $name, Chart::Color::Value::rgb_from_hsl( @hsl ), @hsl ); | |
821 | } | |
822 | ||
823 | sub _add_color { | |
824 | my ($name, @rgb, @hsl) = @_; | |
825 | $name = _clean_name( $name ); | |
826 | return carp "there is already a color named '$name' in store of ".__PACKAGE__ if name_taken( $name ); | |
827 | _add_color_to_reverse_search( $name, @rgb, @hsl); | |
828 | my $ret = $rgbhsl_from_name{$name} = [@rgb, @hsl]; # add to foreward search | |
829 | (ref $ret) ? [@$ret] : ''; # make returned ref not transparent | |
830 | } | |
831 | ||
832 | sub _clean_name { | |
833 | my $name = shift; | |
834 | $name =~ tr/_//d; | |
835 | lc $name; | |
836 | } | |
837 | ||
838 | sub _names_from_rgb { # each of AoAoA cells (if exists) contains name or array with names (shortes first) | |
839 | return '' unless exists $name_from_rgb[ $_[0] ] | |
840 | and exists $name_from_rgb[ $_[0] ][ $_[1] ] and exists $name_from_rgb[ $_[0] ][ $_[1] ][ $_[2] ]; | |
841 | my $cell = $name_from_rgb[ $_[0] ][ $_[1] ][ $_[2] ]; | |
842 | ref $cell ? @$cell : $cell; | |
843 | } | |
844 | ||
845 | sub _names_from_hsl { | |
846 | return '' unless exists $name_from_hsl[ $_[0] ] | |
847 | and exists $name_from_hsl[ $_[0] ][ $_[1] ] and exists $name_from_hsl[ $_[0] ][ $_[1] ][ $_[2] ]; | |
848 | my $cell = $name_from_hsl[ $_[0] ][ $_[1] ][ $_[2] ]; | |
849 | ref $cell ? @$cell : $cell; | |
850 | } | |
851 | ||
852 | sub _add_color_to_reverse_search { # my ($name, @rgb, @hsl) = @_; | |
853 | my $name = $_[0]; | |
854 | my $cell = $name_from_rgb[ $_[1] ][ $_[2] ][ $_[3] ]; | |
855 | if (defined $cell) { | |
856 | if (ref $cell) { | |
857 | if (length $name < length $cell->[0] ) { unshift @$cell, $name } | |
858 | else { push @$cell, $name } | |
859 | } else { | |
860 | $name_from_rgb[ $_[1] ][ $_[2] ][ $_[3] ] = | |
861 | (length $name < length $cell) ? [ $name, $cell ] | |
862 | : [ $cell, $name ] ; | |
863 | } | |
864 | } else { $name_from_rgb[ $_[1] ][ $_[2] ][ $_[3] ] = $name } | |
865 | ||
866 | $cell = $name_from_hsl[ $_[4] ][ $_[5] ][ $_[6] ]; | |
867 | if (defined $cell) { | |
868 | if (ref $cell) { | |
869 | if (length $name < length $cell->[0] ) { unshift @$cell, $name } | |
870 | else { push @$cell, $name } | |
871 | } else { | |
872 | $name_from_hsl[ $_[4] ][ $_[5] ][ $_[6] ] = | |
873 | (length $name < length $cell) ? [ $name, $cell ] | |
874 | : [ $cell, $name ] ; | |
875 | } | |
876 | } else { $name_from_hsl[ $_[4] ][ $_[5] ][ $_[6] ] = $name } | |
877 | } | |
878 | ||
879 | 1; | |
880 | ||
881 | __END__ | |
882 | ||
883 | =pod | |
884 | ||
885 | =head1 NAME | |
886 | ||
887 | Chart::Color::Constant - access values of color constants | |
888 | ||
889 | =head1 SYNOPSIS | |
890 | ||
891 | my @names = Chart::Color::Constant::all_names(); | |
892 | my @rgb = Chart::Color::Constant::rgb_from_name('darkblue'); | |
893 | my @hsl = Chart::Color::Constant::hsl_from_name('darkblue'); | |
894 | ||
895 | Chart::Color::Value::add_rgb('lucky', [0, 100, 50]); | |
896 | ||
897 | =head1 DESCRIPTION | |
898 | ||
899 | RGB and HSL values of named colors from the X11 and HTML standard | |
900 | and Pantone report. Allows also reverse search, storage and conversion | |
901 | of color values. | |
902 | ||
903 | This module is supposed to be used by Chart::Color and not directly | |
904 | by the user (for the most part). It converts a stored color name into | |
905 | its values (rgb, hsl or both) and back. One color can have multiple names. | |
906 | Also nearby (similar) colors can be searched. Own colors can be | |
907 | (none permanently) stored for later reference by name. For this a name | |
908 | has to be chosen, that is not already taken. Independently of that | |
909 | can any color be converted from rgb to hsl and back. | |
910 | ||
911 | =head1 ROUTINES | |
912 | ||
913 | =head2 rgb_from_name | |
914 | ||
915 | Red, Green and Blue value of the named color. | |
916 | These values are integer in 0 .. 255. | |
917 | ||
918 | my @rgb = Chart::Color::Constant::rgb_from_name('darkblue'); | |
919 | @rgb = Chart::Color::Constant::rgb_from_name('dark_blue'); # same result | |
920 | @rgb = Chart::Color::Constant::rgb_from_name('DarkBlue'); # still same | |
921 | ||
922 | =head2 hsl_from_name | |
923 | ||
924 | Hue, saturation and lightness of the named color. | |
925 | These are integer between 0 .. 359 (hue) or 100 (sat. & light.). | |
926 | A hue of 360 and 0 (degree in a cylindrical coordinate system) is | |
927 | considered to be the same, this modul deals only with the ladder. | |
928 | ||
929 | my @hsl = Chart::Color::Constant::hsl_from_name('darkblue'); | |
930 | ||
931 | =head2 name_from_rgb | |
932 | ||
933 | Returns name of color with given rgb value triplet. | |
934 | Returns empty string if color is not stored. When several names define | |
935 | given color, the shortest name will be selected in scalar context. | |
936 | In array context all names are given. | |
937 | ||
938 | say Chart::Color::Constant::name_from_rgb( 15, 10, 121 ); # 'darkblue' | |
939 | say Chart::Color::Constant::name_from_rgb([15, 10, 121]); # works too | |
940 | ||
941 | =head2 name_from_hsl | |
942 | ||
943 | Returns name of color with given hsl value triplet. | |
944 | Returns empty string if color is not stored. When several names define | |
945 | given color, the shortest name will be selected in scalar context. | |
946 | In array context all names are given. | |
947 | ||
948 | say scalar Chart::Color::Constant::name_from_hsl( 0, 100, 50 ); # 'red' | |
949 | scalar Chart::Color::Constant::name_from_hsl([0, 100, 50]); # works too | |
950 | say for Chart::Color::Constant::name_from_hsl( 0, 100, 50 ); # 'red', 'red1' | |
951 | ||
952 | =head2 names_in_hsl_range | |
953 | ||
954 | Color names in selected neighbourhood of hsl color space, that look similar. | |
955 | It requires two arguments. The first one is an array containing three | |
956 | values (hue, saturation and lightness), that define the center of the | |
957 | neighbourhood (searched area). | |
958 | ||
959 | The second argument can either be a number or again an array with | |
960 | three values (h,s and l). If its just a number, it will be the radius r | |
961 | of a ball, that defines the neighbourhood. From all colors inside that | |
962 | ball, that are equal distanced or nearer to the center than r, one | |
963 | name will returned. | |
964 | ||
965 | If the second argument is an array, it has to contain the tolerance | |
966 | (allowed distance) in h, s and l direction. Please note the h dimension | |
967 | is circular: the distance from 355 to 0 is 5. The s and l dimensions are | |
968 | linear, so that a center value of 90 and a tolerance of 15 will result | |
969 | in a search of in the range 75 .. 100. | |
970 | ||
971 | The results contains only one name per color (the shortest). | |
972 | ||
973 | # all bright red'ish clors | |
974 | my @names = Chart::Color::Constant::names_in_hsl_range([0, 90, 50], 5); | |
975 | # approximates to : | |
976 | my @names = Chart::Color::Constant::names_in_hsl_range([0, 90, 50],[ 3, 3, 3]); | |
977 | ||
978 | ||
979 | =head2 all_names | |
980 | ||
981 | A sorted list of all stored color names. | |
982 | ||
983 | =head2 name_taken | |
984 | ||
985 | A perlish pseudo boolean tells if the color name is already in use. | |
986 | ||
987 | =head2 add_rgb | |
988 | ||
989 | Adding a color to the store under an not taken (not already used) name. | |
990 | Arguments are name, red, green and blue value (integer < 256, see rgb). | |
991 | ||
992 | Chart::Color::Constant::add_rgb('nightblue', 15, 10, 121 ); | |
993 | Chart::Color::Constant::add_rgb('nightblue', [15, 10, 121]); | |
994 | ||
995 | =head2 add_hsl | |
996 | ||
997 | Adding a color to the store under an not taken (not already used) name. | |
998 | Arguments are name, hue, saturation and lightness value (see hsl). | |
999 | ||
1000 | Chart::Color::Constant::add_rgb('lucky', 0, 100, 50 ); | |
1001 | Chart::Color::Constant::add_rgb('lucky', [0, 100, 50]); | |
1002 | ||
1003 | =head2 NAMES | |
1004 | ||
1005 | white, black, red, green, blue, yellow, purple, pink, peach, plum, mauve, brown, grey | |
1006 | ||
1007 | aliceblue, antiquewhite, antiquewhite1, antiquewhite2, antiquewhite3, | |
1008 | antiquewhite4, aqua, aquamarine, aquamarine1, aquamarine2, aquamarine3, | |
1009 | aquamarine4, azure, azure1, azure2, azure3, azure4, beige, bisque, bisque1, | |
1010 | bisque2, bisque3, bisque4, blanchedalmond, blue1, blue2, blue3, blue4, | |
1011 | blueviolet, brown1, brown2, brown3, brown4, burlywood, burlywood1, | |
1012 | burlywood2, burlywood3, burlywood4, cadetblue, cadetblue1, cadetblue2, | |
1013 | cadetblue3, cadetblue4, chartreuse, chartreuse1, chartreuse2, chartreuse3, | |
1014 | chartreuse4, chocolate, chocolate1, chocolate2, chocolate3, chocolate4, | |
1015 | coral, coral1, coral2, coral3, coral4, cornflowerblue, cornsilk, cornsilk1, | |
1016 | cornsilk2, cornsilk3, cornsilk4, crimson, cyan, cyan1, cyan2, cyan3, cyan4, | |
1017 | darkblue, darkcyan, darkgoldenrod, darkgoldenrod1, darkgoldenrod2, | |
1018 | darkgoldenrod3, darkgoldenrod4, darkgray, darkgreen, darkkhaki, darkmagenta, | |
1019 | darkolivegreen, darkolivegreen1, darkolivegreen2, darkolivegreen3, | |
1020 | darkolivegreen4, darkorange, darkorange1, darkorange2, darkorange3, | |
1021 | darkorange4, darkorchid, darkorchid1, darkorchid2, darkorchid3, | |
1022 | darkorchid4, darkred, darksalmon, darkseagreen, darkseagreen1, | |
1023 | darkseagreen2, darkseagreen3, darkseagreen4, darkslateblue, darkslategray, | |
1024 | darkslategray1, darkslategray2, darkslategray3, darkslategray4, | |
1025 | darkturquoise, darkviolet, deeppink, deeppink1, deeppink2, deeppink3, | |
1026 | deeppink4, deepskyblue, deepskyblue1, deepskyblue2, deepskyblue3, | |
1027 | deepskyblue4, dimgray, dodgerblue, dodgerblue1, dodgerblue2, dodgerblue3, | |
1028 | dodgerblue4, firebrick, firebrick1, firebrick2, firebrick3, firebrick4, | |
1029 | floralwhite, forestgreen, fuchsia, gainsboro, ghostwhite, gold, gold1, | |
1030 | gold2, gold3, gold4, goldenrod, goldenrod1, goldenrod2, goldenrod3, | |
1031 | goldenrod4, gray, gray1, gray2, gray3, gray4, gray5, gray6, gray7, gray8, | |
1032 | gray9, gray10, gray11, gray12, gray13, gray14, gray15, gray16, gray17, | |
1033 | gray18, gray19, gray20, gray21, gray22, gray23, gray24, gray25, gray26, | |
1034 | gray27, gray28, gray29, gray30, gray31, gray32, gray33, gray34, gray35, | |
1035 | gray36, gray37, gray38, gray39, gray40, gray41, gray42, gray43, gray44, | |
1036 | gray45, gray46, gray47, gray48, gray49, gray50, gray51, gray52, gray53, | |
1037 | gray54, gray55, gray56, gray57, gray58, gray59, gray60, gray61, gray62, | |
1038 | gray63, gray64, gray65, gray66, gray67, gay68, gray69, gray70, gray71, | |
1039 | gray72, gray73, gray74, gray75, gray76, gray77, gray78, gray79, gray80, | |
1040 | gray81, gray82, gray83, gray84, gray85, gray86, gray87, gray88, gray89, | |
1041 | gray90, gray91, gray92, gray93, gray94, gray95, gray97, gray98, gray99, | |
1042 | green1, green2, green3, green4, greenyellow, grey1, grey2, grey3, grey4, | |
1043 | honeydew, honeydew1, honeydew2, honeydew3, honeydew4, hotpink, hotpink1, | |
1044 | hotpink2, hotpink3, hotpink4, indianred, indianred1, indianred2, indianred3, | |
1045 | indianred4, indigo, ivory, ivory1, ivory2, ivory3, ivory4, khaki, khaki1, | |
1046 | khaki2, khaki3, khaki4, lavender, lavenderblush, lavenderblush1, | |
1047 | lavenderblush2, lavenderblush3, lavenderblush4, lawngreen, lemonchiffon, | |
1048 | lemonchiffon1, lemonchiffon2, lemonchiffon3, lemonchiffon4, light, | |
1049 | lightblue, lightblue1, lightblue2, lightblue3,lightblue4, lightcoral, | |
1050 | lightcyan, lightcyan1, lightcyan2, lightcyan3, lightcyan4, lightgoldenrod, | |
1051 | lightgoldenrod1, lightgoldenrod2, lightgoldenrod3, lightgoldenrod4, | |
1052 | lightgray, lightgreen, lightpink, lightpink1, lightpink2, lightpink3, | |
1053 | lightpink4, lightpurple, lightsalmon, lightsalmon1, lightsalmon2, | |
1054 | lightsalmon3, lightsalmon4, lightseagreen, lightskyblue, lightskyblue1, | |
1055 | lightskyblue2, lightskyblue3, lightskyblue4, lightslateblue, lightslategray, | |
1056 | lightsteelblue, lightsteelblue1, lightsteelblue2, lightsteelblue3, | |
1057 | lightsteelblue4, lightyellow, lightyellow1, lightyellow2, lightyellow3, | |
1058 | lightyellow4, lime, limegreen, linen, magenta, magenta1, magenta2, magenta3, | |
1059 | magenta4, maroon, maroon1, maroon2, maroon3, maroon4, medium, | |
1060 | mediumaquamarine, mediumblue, mediumorchid, mediumorchid1, mediumorchid2, | |
1061 | mediumorchid3, mediumorchid4, mediumpurple, mediumpurple1, mediumpurple2, | |
1062 | mediumpurple3, mediumpurple4, mediumseagreen, mediumslateblue, | |
1063 | mediumspringgreen, mediumturquoise, mediumvioletred, midnightblue, | |
1064 | mintcream, mistyrose, mistyrose1, mistyrose2, mistyrose3, mistyrose4, | |
1065 | moccasin, navajowhite, navajowhite1, navajowhite2, navajowhite3, | |
1066 | navajowhite4, navy, navyblue, oldlace, olive, olivedrab, olivedrab1, | |
1067 | olivedrab2, olivedrab3, olivedrab4, orange, orange1, orange2, orange3, | |
1068 | orange4, orangered, orangered1, orangered2, orangered3, orangered4, | |
1069 | orchid, orchid1, orchid2, orchid3, orchid4, pale, palegoldenrod, palegreen, | |
1070 | palegreen1, palegreen2, palegreen3, palegreen4, paleturquoise, | |
1071 | paleturquoise1, paleturquoise2, paleturquoise3, paleturquoise4, | |
1072 | palevioletred, palevioletred1, palevioletred2, palevioletred3, | |
1073 | palevioletred4, papayawhip, peachpuff, peachpuff1, peachpuff2, peachpuff3, | |
1074 | peachpuff4, peru, pink1, pink2, pink3, pink4, plum1, plum2, plum3, plum4, | |
1075 | powderblue, purple1, purple2, purple3, purple4, rebeccapurple, red1, red2, | |
1076 | red3, red4, rosybrown, rosybrown1, rosybrown2, rosybrown3, rosybrown4, | |
1077 | royalblue, royalblue1, royalblue2, royalblue3, royalblue4, saddlebrown, | |
1078 | salmon, salmon1, salmon2, salmon3, salmon4, sandybrown, seagreen, | |
1079 | seagreen1, seagreen2, seagreen3, seagreen4, seashell, seashell1, seashell2, | |
1080 | seashell3, seashell4, sienna, sienna1, sienna2, sienna3, sienna4, silver, | |
1081 | skyblue, skyblue1, skyblue2, skyblue3, skyblue4, slateblue, slateblue1, | |
1082 | slateblue2, slateblue3, slateblue4, slategray, slategray1, slategray2, | |
1083 | slategray3, slategray4, snow, snow1, snow2, snow3, snow4, springgreen, | |
1084 | springgreen1, springgreen2, springgreen3, springgreen4, steelblue, | |
1085 | steelblue1, steelblue2, steelblue3, steelblue4, tan, tan1, tan2, tan3, | |
1086 | tan4, teal, thistle, thistle1, thistle2, thistle3, thistle4, tomato, | |
1087 | tomato1, tomato2, tomato3, tomato4, turquoise, turquoise1, turquoise2, | |
1088 | turquoise3, turquoise4, violet, violetred, violetred1, violetred2, | |
1089 | violetred3, violetred4, wheat, wheat1, wheat2, wheat3, wheat4, whitesmoke, | |
1090 | yellow1, yellow2, yellow3, yellow4, yellowgreen | |
1091 | ||
1092 | marsala, radiandorchid, emerald, tangerinetango, honeysucle, turquoise, | |
1093 | mimosa, blueizis, chilipepper, sanddollar, blueturquoise, tigerlily, | |
1094 | aquasky, truered, fuchsiarose, ceruleanblue, rosequartz, peachecho, | |
1095 | serenity, snorkelblue, limpetshell, lilacgrey, icedcoffee, fiesta, | |
1096 | buttercup, greenflash, riverside, airyblue, sharkskin, aurorared, | |
1097 | warmtaupe, dustycedar, lushmeadow, spicymustard, pottersclay, bodacious, | |
1098 | greenery, niagara, primroseyellow, lapisblue, flame, islandparadise, | |
1099 | paledogwood, pinkyarrow, kale, hazelnut, grenadine, balletslipper, | |
1100 | butterum, navypeony, neutralgray, shadedspruce, goldenlime, marina, | |
1101 | autumnmaple, meadowlark, cherrytomato, littleboyblue, chilioil, | |
1102 | pinklavender, bloomingdahlia, arcadia, ultraviolet, emperador, | |
1103 | almostmauve, springcrocus, sailorblue, harbormist, warmsand, coconutmilk, | |
1104 | redpear, valiantpoppy, nebulasblue, ceylonyellow, martiniolive, | |
1105 | russetorange, crocuspetal, limelight, quetzalgreen, sargassosea, tofu, | |
1106 | almondbuff, quietgray, meerkat, fiesta, jesterred, turmeric, livingcoral, | |
1107 | pinkpeacock, pepperstem, aspengold, princessblue, toffee, mangomojito, | |
1108 | terrariummoss, sweetlilac, soybean, eclipse, sweetcorn, browngranite, | |
1109 | chilipepper, bikingred, peachpink, rockyroad, fruitdove, sugaralmond, | |
1110 | darkcheddar, galaxyblue, bluestone, orangetiger, eden, vanillacustard, | |
1111 | eveningblue, paloma, guacamole, flamescarlet, saffron, biscaygreen, chive, | |
1112 | fadeddenim, orangepeel, mosaicblue, sunlight, coralpink, grapecompote, | |
1113 | lark, navyblazer, brilliantwhite, ash, amberglow, samba, sandstone, | |
1114 | classicblue, greensheen, rosetan, ultramarinegreen, firedbrick, | |
1115 | peachnougat, magentapurple, marigold, cerulean, rust, illuminating, | |
1116 | frenchblue, greenash, burntcoral, mint, amethystorchid, raspberrysorbet, | |
1117 | inkwell, ultimategray, buttercream, desertmist, willow | |
1118 | ||
1119 | =for HTML <p> | |
1120 | <img src="https://raw.githubusercontent.com/lichtkind/Chart/main/dev/function/color/table/color_table0.png" alt="color table 1"> | |
1121 | <img src="https://raw.githubusercontent.com/lichtkind/Chart/main/dev/function/color/table/color_table1.png" alt="color table 2"> | |
1122 | <img src="https://raw.githubusercontent.com/lichtkind/Chart/main/dev/function/color/table/color_table2.png" alt="color table 3"> | |
1123 | <img src="https://raw.githubusercontent.com/lichtkind/Chart/main/dev/function/color/table/color_table3.png" alt="color table 4"> | |
1124 | </p> | |
1125 | ||
1126 | =head1 COPYRIGHT & LICENSE | |
1127 | ||
1128 | Copyright 2022 Herbert Breunung. | |
1129 | ||
1130 | This program is free software; you can redistribute it and/or modify it | |
1131 | under same terms as Perl itself. | |
1132 | ||
1133 | =head1 AUTHOR | |
1134 | ||
1135 | Herbert Breunung, <lichtkind@cpan.org> |
0 | use v5.12; | |
1 | ||
2 | # check, convert and measure color values | |
3 | ||
4 | package Chart::Color::Value; | |
5 | our $VERSION = 'v2.403.7'; | |
6 | use Carp; | |
7 | ||
8 | sub check_rgb { # carp returns 1 | |
9 | my (@rgb) = @_; | |
10 | my $help = 'has to be an integer between 0 and 255'; | |
11 | return carp "need exactly 3 positive integer values 0 <= n < 256 for rgb input" unless @rgb == 3; | |
12 | return carp "red value $rgb[0] ".$help unless int $rgb[0] == $rgb[0] and $rgb[0] >= 0 and $rgb[0] < 256; | |
13 | return carp "green value $rgb[1] ".$help unless int $rgb[1] == $rgb[1] and $rgb[1] >= 0 and $rgb[1] < 256; | |
14 | return carp "blue value $rgb[2] ".$help unless int $rgb[2] == $rgb[2] and $rgb[2] >= 0 and $rgb[2] < 256; | |
15 | 0; | |
16 | } | |
17 | ||
18 | sub check_hsl { | |
19 | my (@hsl) = @_; | |
20 | my $help = 'has to be an integer between 0 and'; | |
21 | return carp "need exactly 3 positive integer between 0 and 359 or 99 for hsl input" unless @hsl == 3; | |
22 | return carp "hue value $hsl[0] $help 359" unless int $hsl[0] == $hsl[0] and $hsl[0] >= 0 and $hsl[0] < 360; | |
23 | return carp "saturation value $hsl[1] $help 100" unless int $hsl[1] == $hsl[1] and $hsl[1] >= 0 and $hsl[1] < 101; | |
24 | return carp "lightness value $hsl[2] $help 100" unless int $hsl[2] == $hsl[2] and $hsl[2] >= 0 and $hsl[2] < 101; | |
25 | 0; | |
26 | } | |
27 | ||
28 | sub trim_rgb { # cut values into the domain of definition of 0 .. 255 | |
29 | my (@rgb) = @_; | |
30 | return (0,0,0) unless @rgb == 3; | |
31 | for (0..2){ | |
32 | $rgb[$_] = 0 if $rgb[$_] < 0; | |
33 | $rgb[$_] = 255 if $rgb[$_] > 255; | |
34 | } | |
35 | $rgb[$_] = round($rgb[$_]) for 0..2; | |
36 | @rgb; | |
37 | } | |
38 | ||
39 | sub trim_hsl { # cut values into 0 ..359, 0 .. 100, 0 .. 100 | |
40 | my (@hsl) = @_; | |
41 | return (0,0,0) unless @hsl == 3; | |
42 | $hsl[0] += 360 while $hsl[0] < 0; | |
43 | $hsl[0] -= 360 while $hsl[0] >= 360; | |
44 | for (1..2){ | |
45 | $hsl[$_] = 0 if $hsl[$_] < 0; | |
46 | $hsl[$_] = 100 if $hsl[$_] > 100; | |
47 | } | |
48 | $hsl[$_] = round($hsl[$_]) for 0..2; | |
49 | @hsl; | |
50 | } | |
51 | ||
52 | sub difference_rgb { # \@rgb, \@rgb --> @rgb distance as vector | |
53 | my ($rgb, $rgb2) = @_; | |
54 | return carp "need two triplets of rgb values in 2 arrays to compute rgb differences" | |
55 | unless ref $rgb eq 'ARRAY' and @$rgb == 3 and ref $rgb2 eq 'ARRAY' and @$rgb2 == 3; | |
56 | check_rgb(@$rgb) and return; | |
57 | check_rgb(@$rgb2) and return; | |
58 | (abs($rgb->[0] - $rgb2->[0]), abs($rgb->[1] - $rgb2->[1]), abs($rgb->[2] - $rgb2->[2]) ); | |
59 | } | |
60 | ||
61 | sub difference_hsl { # \@hsl, \@hsl --> $d | |
62 | my ($hsl, $hsl2) = @_; | |
63 | return carp "need two triplets of hsl values in 2 arrays to compute hsl differences" | |
64 | unless ref $hsl eq 'ARRAY' and @$hsl == 3 and ref $hsl2 eq 'ARRAY' and @$hsl2 == 3; | |
65 | check_hsl(@$hsl) and return; | |
66 | check_hsl(@$hsl2) and return; | |
67 | my $delta_h = abs($hsl->[0] - $hsl2->[0]); | |
68 | $delta_h = 360 - $delta_h if $delta_h > 180; | |
69 | ($delta_h, abs($hsl->[1] - $hsl2->[1]), abs($hsl->[2] - $hsl2->[2]) ); | |
70 | } | |
71 | ||
72 | sub distance_rgb { # \@rgb, \@rgb --> $d | |
73 | return carp "need two triplets of rgb values in 2 arrays to compute rgb distance " if @_ != 2; | |
74 | my @delta_rgb = difference_rgb( $_[0], $_[1] ); | |
75 | return unless @delta_rgb == 3; | |
76 | sqrt($delta_rgb[0] ** 2 + $delta_rgb[1] ** 2 + $delta_rgb[2] ** 2); | |
77 | } | |
78 | ||
79 | sub distance_hsl { # \@hsl, \@hsl --> $d | |
80 | return carp "need two triplets of hsl values in 2 arrays to compute hsl distance " if @_ != 2; | |
81 | my @delta_hsl = difference_hsl( $_[0], $_[1] ); | |
82 | return unless @delta_hsl == 3; | |
83 | sqrt($delta_hsl[0] ** 2 + $delta_hsl[1] ** 2 + $delta_hsl[2] ** 2); | |
84 | } | |
85 | ||
86 | sub hsl_from_rgb { # convert color value triplet (int --> int), (real --> real) if $real | |
87 | my (@rgb) = @_; | |
88 | my $real = ''; | |
89 | if (ref $rgb[0] eq 'ARRAY'){ | |
90 | @rgb = @{$rgb[0]}; | |
91 | $real = $rgb[1] // $real; | |
92 | } | |
93 | check_rgb( @rgb ) and return unless $real; | |
94 | my @hsl = _hsl_from_rgb( @rgb ); | |
95 | return @hsl if $real; | |
96 | ( round( $hsl[0] ), round( $hsl[1] ), round( $hsl[2] ) ); | |
97 | } | |
98 | ||
99 | sub rgb_from_hsl { # convert color value triplet (int > int), (real > real) if $real | |
100 | my (@hsl) = @_; | |
101 | my $real = ''; | |
102 | if (ref $hsl[0] eq 'ARRAY'){ | |
103 | @hsl = @{$hsl[0]}; | |
104 | $real = $hsl[1] // $real; | |
105 | } | |
106 | check_hsl( @hsl ) and return unless $real; | |
107 | my @rgb = _rgb_from_hsl( @hsl ); | |
108 | return @rgb if $real; | |
109 | ( round( $rgb[0] ), round( $rgb[1] ), round( $rgb[2] ) ); | |
110 | } | |
111 | ||
112 | sub hex_from_rgb { return unless @_ == 3; sprintf "#%02x%02x%02x", @_ } | |
113 | sub rgb_from_hex { # translate #000000 and #000 --> r, g, b | |
114 | my $hex = shift; | |
115 | return carp "hex color definition '$hex' has to start with # followed by 3 or 6 hex characters (0-9,a-f)" | |
116 | unless defined $hex and (length($hex) == 4 or length($hex) == 7) and $hex =~ /^#[\da-f]+$/i; | |
117 | $hex = substr $hex, 1; | |
118 | (length $hex == 3) ? (map { hex($_.$_) } unpack( "a1 a1 a1", $hex)) | |
119 | : (map { hex($_ ) } unpack( "a2 a2 a2", $hex)); | |
120 | } | |
121 | ||
122 | sub _hsl_from_rgb { # float conversion | |
123 | my (@rgb) = @_; | |
124 | my ($maxi, $mini) = (0 , 1); # index of max and min value in @rgb | |
125 | if ($rgb[1] > $rgb[0]) { ($maxi, $mini ) = ($mini, $maxi ) } | |
126 | if ($rgb[2] > $rgb[$maxi]) { $maxi = 2 } | |
127 | elsif ($rgb[2] < $rgb[$mini]) { $mini = 2 } | |
128 | my $delta = $rgb[$maxi] - $rgb[$mini]; | |
129 | my $avg = ($rgb[$maxi] + $rgb[$mini]) / 2; | |
130 | my $H = !$delta ? 0 : (2 * $maxi + (($rgb[($maxi+1) % 3] - $rgb[($maxi+2) % 3]) / $delta)) * 60; | |
131 | $H += 360 if $H < 0; | |
132 | my $S = ($avg == 0) ? 0 : ($avg == 255) ? 0 : $delta / (255 - abs((2 * $avg) - 255)); | |
133 | ($H, $S * 100, $avg * 0.392156863 ); | |
134 | } | |
135 | ||
136 | sub _rgb_from_hsl { # float conversion | |
137 | my (@hsl) = @_; | |
138 | $hsl[0] /= 60; | |
139 | my $C = $hsl[1] * (100 - abs($hsl[2] * 2 - 100)) * 0.0255; | |
140 | my $X = $C * (1 - abs($hsl[0] % 2 - 1 + ($hsl[0] - int $hsl[0]))); | |
141 | my $m = ($hsl[2] * 2.55) - ($C / 2); | |
142 | return ($hsl[0] < 1) ? ($C + $m, $X + $m, $m) | |
143 | : ($hsl[0] < 2) ? ($X + $m, $C + $m, $m) | |
144 | : ($hsl[0] < 3) ? ( $m, $C + $m, $X + $m) | |
145 | : ($hsl[0] < 4) ? ( $m, $X + $m, $C + $m) | |
146 | : ($hsl[0] < 5) ? ($X + $m, $m, $C + $m) | |
147 | : ($C + $m, $m, $X + $m); | |
148 | } | |
149 | ||
150 | my $half = 0.50000000000008; | |
151 | ||
152 | sub round { | |
153 | $_[0] >= 0 ? int ($_[0] + $half) | |
154 | : int ($_[0] - $half) | |
155 | } | |
156 | ||
157 | ||
158 | 1; | |
159 | ||
160 | __END__ | |
161 | ||
162 | =pod | |
163 | ||
164 | =head1 NAME | |
165 | ||
166 | Chart::Color::Value - check, convert and measure color values | |
167 | ||
168 | =head1 SYNOPSIS | |
169 | ||
170 | my @names = Chart::Color::Value::all_names(); | |
171 | my @rgb = Chart::Color::Value::rgb_from_name('darkblue'); | |
172 | my @hsl = Chart::Color::Value::hsl_from_name('darkblue'); | |
173 | my @hsl2 = Chart::Color::Value::hsl_from_rgb( 5 ,10, 100); | |
174 | my $d = Chart::Color::Value::distance_hsl( \@hsl, \@hsl2); | |
175 | ||
176 | Chart::Color::Value::add_rgb('lucky', [0, 100, 50]); | |
177 | ||
178 | ||
179 | =head1 DESCRIPTION | |
180 | ||
181 | RGB and HSL values of named colors from the X11 and HTML standard | |
182 | and Pantone report. Allows also reverse search, storage and conversion | |
183 | of color values. | |
184 | ||
185 | This module is supposed to be used by Chart::Color and not directly | |
186 | by the user (for the most part). It converts a stored color name into | |
187 | its values (rgb, hsl or both) and back. One color can have multiple names. | |
188 | Also nearby (similar) colors can be searched. Own colors can be | |
189 | (none permanently) stored for later reference by name. For this a name | |
190 | has to be chosen, that is not already taken. Independently of that | |
191 | can any color be converted from rgb to hsl and back. | |
192 | ||
193 | ||
194 | =head1 ROUTINES | |
195 | ||
196 | =head2 check_rgb | |
197 | ||
198 | Return error message if RGB value triplet is not valid (in range). | |
199 | ||
200 | =head2 check_hsl | |
201 | ||
202 | Return error message if HSL value triplet is not valid (in range). | |
203 | ||
204 | ||
205 | =head2 trim_rgb | |
206 | ||
207 | Change RGB triplet to the nearest valid values. | |
208 | ||
209 | =head2 trim_hsl | |
210 | ||
211 | Change HSL triplet to the nearest valid values. | |
212 | ||
213 | ||
214 | =head2 hsl_from_rgb | |
215 | ||
216 | Converting an rgb value triplet into the corresponding hsl | |
217 | ||
218 | Red, Green and Blue are integer in 0 .. 255. | |
219 | Hue is an integer between 0 .. 359 (hue) | |
220 | and saturation and lightness are 0 .. 100 (percentage). | |
221 | A hue of 360 and 0 (degree in a cylindrical coordinate system) is | |
222 | considered to be the same, this modul deals only with the ladder. | |
223 | ||
224 | =head2 rgb_from_hsl | |
225 | ||
226 | Converting an hsl value triplet into the corresponding rgb | |
227 | (see rgb_from_name and hsl_from_name). Please not that back and forth | |
228 | conversion can lead to drifting results due to rounding. | |
229 | ||
230 | my @rgb = Chart::Color::Value::rgb_from_hsl(0, 90, 50); | |
231 | my @rgb = Chart::Color::Value::rgb_from_hsl([0, 90, 50]); # works too | |
232 | # for real (none integer results), any none zero value works as second arg | |
233 | my @rgb = Chart::Color::Value::rgb_from_hsl([0, 90, 50], 'real'); | |
234 | ||
235 | =head2 distance_rgb | |
236 | ||
237 | Distance in (linear) rgb color space between two coordinates. | |
238 | ||
239 | ||
240 | my $d = Chart::Color::Value::distance_rgb([1,1,1], [2,2,2]); # approx 1.7 | |
241 | ||
242 | ||
243 | =head2 distance_hsl | |
244 | ||
245 | Distance in (cylindrical) hsl color space between two coordinates. | |
246 | ||
247 | my $d = Chart::Color::Value::distance_rgb([1,1,1], [356, 3, 2]); # approx 6 | |
248 | ||
249 | ||
250 | =head1 COPYRIGHT & LICENSE | |
251 | ||
252 | Copyright 2022 Herbert Breunung. | |
253 | ||
254 | This program is free software; you can redistribute it and/or modify it | |
255 | under same terms as Perl itself. | |
256 | ||
257 | =head1 AUTHOR | |
258 | ||
259 | Herbert Breunung, <lichtkind@cpan.org> | |
260 | ||
261 | =cut |
0 | ||
1 | # Chart::Color: read only color holding object | |
2 | # with methods for relation, mixing and transitions | |
3 | ||
4 | use v5.12; | |
5 | ||
6 | package Chart::Color; | |
7 | our $VERSION = 'v2.403.7'; | |
8 | ||
9 | use Carp; | |
10 | use Chart::Color::Constant; | |
11 | ||
12 | my $new_help = 'constructor of Chart::Color object needs either:'. | |
13 | ' 1. RGB or HSL hash or ref: ->new(r => 255, g => 0, b => 0), ->new({ h => 0, s => 100, l => 50 })'. | |
14 | ' 2. RGB array or ref: ->new( [255, 0, 0 ]) or >new( 255, 0, 0 )'. | |
15 | ' 3. hex form "#FF0000" or "#f00" 4. a name: "red" or "SVG:red".'; | |
16 | ||
17 | ## constructor ######################################################### | |
18 | ||
19 | sub new { | |
20 | my ($pkg, @args) = @_; | |
21 | @args = ([@args]) if @args == 3; | |
22 | @args = ({ $args[0] => $args[1], $args[2] => $args[3], $args[4] => $args[5] }) if @args == 6; | |
23 | return carp $new_help unless @args == 1; | |
24 | _new_from_scalar($args[0]); | |
25 | } | |
26 | sub _new_from_scalar { | |
27 | my ($arg) = shift; | |
28 | my $name; | |
29 | if (not ref $arg){ # resolve 'color_name' or '#RRGGBB' -> ($r, $g, $b) | |
30 | my @rgb = _rgb_from_name_or_hex($arg); | |
31 | return unless @rgb == 3; | |
32 | $name = $arg if index( $arg, ':') > -1; | |
33 | $arg = { r => $rgb[0], g => $rgb[1], b => $rgb[2] }; | |
34 | } elsif (ref $arg eq 'ARRAY'){ | |
35 | return carp "need exactly 3 RGB numbers!" unless @$arg == 3; | |
36 | $arg = { r => $arg->[0], g => $arg->[1], b => $arg->[2] }; | |
37 | } | |
38 | return carp $new_help unless ref $arg eq 'HASH' and keys %$arg == 3; | |
39 | my %named_arg = map { _shrink_key($_) => $arg->{$_} } keys %$arg; # reduce keys to lc first char | |
40 | ||
41 | my (@rgb, @hsl); | |
42 | if (exists $named_arg{'r'} and exists $named_arg{'g'} and exists $named_arg{'b'}) { | |
43 | @rgb = Chart::Color::Value::trim_rgb(@named_arg{qw/r g b/}); | |
44 | @hsl = Chart::Color::Value::hsl_from_rgb( @rgb ); | |
45 | } elsif (exists $named_arg{'h'} and exists $named_arg{'s'} and exists $named_arg{'l'}) { | |
46 | @hsl = Chart::Color::Value::trim_hsl( @named_arg{qw/h s l/}); | |
47 | @rgb = Chart::Color::Value::rgb_from_hsl( @hsl ); | |
48 | } else { return carp "argument keys need to be r, g and b or h, s and l (long names and upper case work too!)" } | |
49 | $name = Chart::Color::Constant::name_from_rgb( @rgb ) unless defined $name; | |
50 | bless [$name, @rgb, @hsl]; | |
51 | } | |
52 | sub _rgb_from_name_or_hex { | |
53 | my $arg = shift; | |
54 | my $i = index( $arg, ':'); | |
55 | if (substr($arg, 0, 1) eq '#'){ # resolve #RRGGBB -> ($r, $g, $b) | |
56 | return Chart::Color::Value::rgb_from_hex( $arg ); | |
57 | } elsif ($i > -1 ){ # resolve pallet:name -> ($r, $g, $b) | |
58 | my $pallet_name = substr $arg, 0, $i-1; | |
59 | my $color_name = substr $arg, $i+1; | |
60 | ||
61 | my $module_base = 'Graphics::ColorNames'; | |
62 | eval "use $module_base"; | |
63 | return carp "$module_base is not installed, but it's needed to load external colors" if $@; | |
64 | ||
65 | my $module = $module_base.'::'.$pallet_name; | |
66 | eval "use $module"; | |
67 | return carp "$module is not installed, to load color '$color_name'" if $@; | |
68 | ||
69 | my $pal = Graphics::ColorNames->new( $pallet_name ); | |
70 | my @rgb = $pal->rgb( $color_name ); | |
71 | return carp "color '$color_name' was not found, propably not part of $module" unless @rgb == 3; | |
72 | @rgb; | |
73 | } else { # resolve name -> ($r, $g, $b) | |
74 | my @rgb = Chart::Color::Constant::rgb_from_name( $arg ); | |
75 | carp "'$arg' is an unknown color name, please check Chart::Color::Constant::all_names()." unless @rgb == 3; | |
76 | @rgb; | |
77 | } | |
78 | } | |
79 | ||
80 | ## getter ############################################################## | |
81 | ||
82 | sub name { $_[0][0] } | |
83 | sub red { $_[0][1] } | |
84 | sub green { $_[0][2] } | |
85 | sub blue { $_[0][3] } | |
86 | sub hue { $_[0][4] } | |
87 | sub saturation { $_[0][5] } | |
88 | sub lightness { $_[0][6] } | |
89 | sub string { $_[0][0] ? $_[0][0] : "[ $_[0][1], $_[0][2], $_[0][3] ]" } | |
90 | ||
91 | sub hsl { @{$_[0]}[4 .. 6] } | |
92 | sub rgb { @{$_[0]}[1 .. 3] } | |
93 | sub rgb_hex { Chart::Color::Value::hex_from_rgb( $_[0]->rgb() ) } | |
94 | ||
95 | ## methods ############################################################## | |
96 | ||
97 | sub distance_to { | |
98 | my ($self, $c2, $metric) = @_; | |
99 | return croak "missing argument: color object or scalar color definition" unless defined $c2; | |
100 | $c2 = (ref $c2 eq __PACKAGE__) ? $c2 : Chart::Color->new( $c2 ); | |
101 | return unless ref $c2 eq __PACKAGE__; | |
102 | ||
103 | return Chart::Color::Value::distance_hsl( [$self->hsl], [$c2->hsl] ) unless defined $metric; | |
104 | $metric = lc $metric; | |
105 | return Chart::Color::Value::distance_hsl( [$self->hsl], [$c2->hsl] ) if $metric eq 'hsl'; | |
106 | return Chart::Color::Value::distance_rgb( [$self->rgb], [$c2->rgb] ) if $metric eq 'rgb'; | |
107 | my @delta_rgb = Chart::Color::Value::difference_rgb( [$self->rgb], [$c2->rgb] ); | |
108 | my @delta_hsl = Chart::Color::Value::difference_hsl( [$self->hsl], [$c2->hsl] ); | |
109 | my $help = "unknown distance metric: $metric. try r, g, b, rg, rb, gb, rgb, h, s, l, hs, hl, sl, hsl (default)."; | |
110 | if (length $metric == 2){ | |
111 | if ($metric eq 'hs' or $metric eq 'sh') {return sqrt( $delta_hsl[0] ** 2 + $delta_hsl[1] ** 2 )} | |
112 | elsif ($metric eq 'hl' or $metric eq 'lh') {return sqrt( $delta_hsl[0] ** 2 + $delta_hsl[2] ** 2 )} | |
113 | elsif ($metric eq 'sl' or $metric eq 'ls') {return sqrt( $delta_hsl[1] ** 2 + $delta_hsl[2] ** 2 )} | |
114 | elsif ($metric eq 'rg' or $metric eq 'gr') {return sqrt( $delta_rgb[0] ** 2 + $delta_rgb[1] ** 2 )} | |
115 | elsif ($metric eq 'rb' or $metric eq 'br') {return sqrt( $delta_rgb[0] ** 2 + $delta_rgb[2] ** 2 )} | |
116 | elsif ($metric eq 'gb' or $metric eq 'bg') {return sqrt( $delta_rgb[1] ** 2 + $delta_rgb[2] ** 2 )} | |
117 | } | |
118 | $metric = substr $metric, 0, 1; | |
119 | $metric eq 'h' ? $delta_hsl[0] : | |
120 | $metric eq 's' ? $delta_hsl[1] : | |
121 | $metric eq 'l' ? $delta_hsl[2] : | |
122 | $metric eq 'r' ? $delta_rgb[0] : | |
123 | $metric eq 'g' ? $delta_rgb[1] : | |
124 | $metric eq 'b' ? $delta_rgb[2] : croak $help; | |
125 | } | |
126 | ||
127 | sub add { | |
128 | my ($self, @args) = @_; | |
129 | my $add_help = 'Chart::Color->add argument options: 1. a color object with optional factor as second arg, '. | |
130 | '2. a color name as string, 3. a color hex definition as in "#FF0000"'. | |
131 | '4. a list of thre values (RGB) (also in an array ref)'. | |
132 | '5. a hash with RGB and HSL keys (as in new, but can be mixed) (also in an hash ref).'; | |
133 | if ((@args == 1 or @args == 2) and ref $args[0] ne 'HASH'){ | |
134 | my @add_rgb; | |
135 | if (ref $args[0] eq __PACKAGE__){ | |
136 | @add_rgb = $args[0]->rgb; | |
137 | } elsif (ref $args[0] eq 'ARRAY'){ | |
138 | @add_rgb = @{$args[0]}; | |
139 | return carp "array ref argument needs to have 3 numerical values (RGB) in it." unless @add_rgb == 3; | |
140 | } elsif (not ref $args[0] and not $args[0] =~ /^\d/){ | |
141 | @add_rgb = _rgb_from_name_or_hex($args[0]); | |
142 | return unless @add_rgb > 1; | |
143 | } else { return carp $add_help } | |
144 | @add_rgb = ($add_rgb[0] * $args[1], $add_rgb[1] * $args[1], $add_rgb[2] * $args[1]) if defined $args[1]; | |
145 | @args = @add_rgb; | |
146 | } | |
147 | my @rgb = $self->rgb; | |
148 | if (@args == 3) { | |
149 | @rgb = Chart::Color::Value::trim_rgb( $rgb[0] + $args[0], $rgb[1] + $args[1], $rgb[2] + $args[2]); | |
150 | return Chart::Color->new( @rgb ); | |
151 | } | |
152 | return carp $add_help unless @args and ((@args % 2 == 0) or (ref $args[0] eq 'HASH')); | |
153 | my %arg = ref $args[0] eq 'HASH' ? %{$args[0]} : @args; | |
154 | my %named_arg = map {_shrink_key($_) => $arg{$_}} keys %arg; # clean keys | |
155 | $rgb[0] += delete $named_arg{'r'} // 0; | |
156 | $rgb[1] += delete $named_arg{'g'} // 0; | |
157 | $rgb[2] += delete $named_arg{'b'} // 0; | |
158 | return Chart::Color->new( Chart::Color::Value::trim_rgb( @rgb ) ) unless %named_arg; | |
159 | my @hsl = Chart::Color::Value::_hsl_from_rgb( @rgb ); | |
160 | $hsl[0] += delete $named_arg{'h'} // 0; | |
161 | $hsl[1] += delete $named_arg{'s'} // 0; | |
162 | $hsl[2] += delete $named_arg{'l'} // 0; | |
163 | if (%named_arg) { | |
164 | my @nrkey = grep {/^\d+$/} keys %named_arg; | |
165 | return carp "wrong number of numerical arguments (only 3 needed)" if @nrkey; | |
166 | carp "got unknown hash key starting with", map {' '.$_} keys %named_arg; | |
167 | } | |
168 | @hsl = Chart::Color::Value::trim_hsl( @hsl ); | |
169 | Chart::Color->new({ H => $hsl[0], S => $hsl[1], L => $hsl[2] }); | |
170 | } | |
171 | ||
172 | sub blend_with { | |
173 | my ($self, $c2, $pos) = @_; | |
174 | return carp "need color object or definition as first argument" unless defined $c2; | |
175 | $c2 = (ref $c2 eq __PACKAGE__) ? $c2 : _new_from_scalar( $c2 ); | |
176 | return unless ref $c2 eq __PACKAGE__; | |
177 | $pos //= 0.5; | |
178 | my $delta_hue = $c2->hue - $self->hue; | |
179 | $delta_hue -= 360 if $delta_hue > 180; | |
180 | $delta_hue += 360 if $delta_hue < -180; | |
181 | my @hsl = ( $self->hue + ($pos * $delta_hue), | |
182 | $self->saturation + ($pos * ($c2->saturation - $self->saturation)), | |
183 | $self->lightness + ($pos * ($c2->lightness - $self->lightness)) | |
184 | ); | |
185 | @hsl = Chart::Color::Value::trim_hsl( @hsl ); | |
186 | Chart::Color->new({ H => $hsl[0], S => $hsl[1], L => $hsl[2] }); | |
187 | } | |
188 | ||
189 | ||
190 | sub gradient_to { | |
191 | my ($self, $c2, $steps, $power) = @_; | |
192 | return carp "need color object or definition as first argument" unless defined $c2; | |
193 | $c2 = (ref $c2 eq __PACKAGE__) ? $c2 : _new_from_scalar( $c2 ); | |
194 | return unless ref $c2 eq __PACKAGE__; | |
195 | $steps //= 3; | |
196 | $power //= 1; | |
197 | return carp "third argument (dynamics), has to be positive (>= 0)" if $power <= 0; | |
198 | return $self if $steps == 1; | |
199 | my @colors = (); | |
200 | my @delta_hsl = ($c2->hue - $self->hue, $c2->saturation - $self->saturation, | |
201 | $c2->lightness - $self->lightness ); | |
202 | $delta_hsl[0] -= 360 if $delta_hsl[0] > 180; | |
203 | $delta_hsl[0] += 360 if $delta_hsl[0] < -180; | |
204 | for my $i (1 .. $steps-2){ | |
205 | my $pos = ($i / ($steps-1)) ** $power; | |
206 | my @hsl = ( $self->hue + ($pos * $delta_hsl[0]), | |
207 | $self->saturation + ($pos * $delta_hsl[1]), | |
208 | $self->lightness + ($pos * $delta_hsl[2])); | |
209 | @hsl = Chart::Color::Value::trim_hsl( @hsl ); | |
210 | push @colors, Chart::Color->new({ H => $hsl[0], S => $hsl[1], L => $hsl[2] }); | |
211 | } | |
212 | $self, @colors, $c2; | |
213 | } | |
214 | ||
215 | sub complementary { | |
216 | my ($self) = shift; | |
217 | my ($count) = int ((shift // 1) + 0.5); | |
218 | my ($saturation_change) = shift // 0; | |
219 | my ($lightness_change) = shift // 0; | |
220 | my @hsl2 = my @hsl_l = my @hsl_r = $self->hsl; | |
221 | $hsl2[0] += 180; | |
222 | $hsl2[1] += $saturation_change; | |
223 | $hsl2[2] += $lightness_change; | |
224 | @hsl2 = Chart::Color::Value::trim_hsl( @hsl2 ); # HSL of C2 | |
225 | my $c2 = Chart::Color->new({ h => $hsl2[0], s => $hsl2[1], l => $hsl2[2] }); | |
226 | return $c2 if $count < 2; | |
227 | my (@colors_r, @colors_l); | |
228 | my @delta = (360 / $count, (($hsl2[1] - $hsl_r[1]) * 2 / $count), (($hsl2[2] - $hsl_r[2]) * 2 / $count) ); | |
229 | for (1 .. ($count - 1) / 2){ | |
230 | $hsl_r[$_] += $delta[$_] for 0..2; | |
231 | $hsl_l[0] -= $delta[0]; | |
232 | $hsl_l[$_] = $hsl_r[$_] for 1,2; | |
233 | $hsl_l[0] += 360 if $hsl_l[0] < 0; | |
234 | $hsl_r[0] -= 360 if $hsl_l[0] >= 360; | |
235 | push @colors_r, Chart::Color->new({ H => $hsl_r[0], S => $hsl_r[1], L => $hsl_r[2] }); | |
236 | unshift @colors_l, Chart::Color->new({ H => $hsl_l[0], S => $hsl_l[1], L => $hsl_l[2] }); | |
237 | } | |
238 | push @colors_r, $c2 unless $count % 2; | |
239 | $self, @colors_r, @colors_l; | |
240 | } | |
241 | ||
242 | sub _shrink_key { lc substr( $_[0], 0, 1 ) } | |
243 | ||
244 | 1; | |
245 | ||
246 | __END__ | |
247 | ||
248 | =pod | |
249 | ||
250 | =head1 NAME | |
251 | ||
252 | Chart::Color - read only single color holding objects | |
253 | ||
254 | =head1 SYNOPSIS | |
255 | ||
256 | my $red = Chart::Color->new('red'); | |
257 | say $red->add('blue')->name; # magenta, mixed in RGB space | |
258 | Chart::Color->new( 0, 0, 255)->hsl # 240, 100, 50 = blue | |
259 | $blue->blend_with({H=> 0, S=> 0, L=> 80}, 0.1);# mix blue with a little grey | |
260 | $red->gradient( '#0000FF', 10); # 10 colors from red to blue | |
261 | $red->complementary( 3 ); # get fitting red green and blue | |
262 | ||
263 | =head1 DESCRIPTION | |
264 | ||
265 | This module is designed for internal usage. It handles also all color | |
266 | definitions done by users with method "$chart->set(color => {...})". | |
267 | To see which formats are allowed there, read the next section and please | |
268 | note that ->set() handles only scalar values. | |
269 | ||
270 | =head1 CONSTRUCTOR | |
271 | ||
272 | There are many options to create a color objects. In short you can | |
273 | either use the name of a predefined constant or provide values in RGB | |
274 | or HSL color space. | |
275 | ||
276 | =head2 new( 'name' ) | |
277 | ||
278 | Get a color by providing a name from the X11 or HTML (SVG) standard or | |
279 | a Pantone report. Upper/Camel case will be treated as lower case and | |
280 | inserted underscore letters ('_') will be ignored as perl does in | |
281 | numbers (1_000 == 1000) (see more under L<Chart::Color::Constant>). | |
282 | ||
283 | my $color = Chart::Color->new('Emerald'); | |
284 | my @names = Chart::Color::Constant::all_names(); # select from these | |
285 | ||
286 | =head2 new( 'standard:color' ) | |
287 | ||
288 | Get a color by name from a specific standard as provided by an external | |
289 | module L<Graphics::ColorNames>::* , which has to be installed separately. | |
290 | * is a placeholder for the pallet name, which might be: Crayola, CSS, | |
291 | EmergyC, GrayScale, HTML, IE, SVG, Werner, WWW or X. In ladder case | |
292 | Graphics::ColorNames::X has to be installed. | |
293 | ||
294 | my $color = Chart::Color->new('SVG:green'); | |
295 | my @s = Graphics::ColorNames::all_schemes(); # installed pallets | |
296 | ||
297 | =head2 new( '#rgb' ) | |
298 | ||
299 | Color definitions in hexadecimal format as widely used in the web, are | |
300 | also acceptable. | |
301 | ||
302 | my $color = Chart::Color->new('#FF0000'); | |
303 | my $color = Chart::Color->new('#f00'); # works too | |
304 | ||
305 | ||
306 | =head2 new( [$r, $g, $b] ) | |
307 | ||
308 | Triplet of integer RGB values (L</red>, L</green> and L</blue> : 0 .. 255). | |
309 | Out of range values will be corrected to the closest value in range. | |
310 | ||
311 | ||
312 | my $red = Chart::Color->new( 255, 0, 0 ); | |
313 | my $red = Chart::Color->new([255, 0, 0]); # does the same | |
314 | ||
315 | ||
316 | =head2 new( {r => $r, g => $g, b => $b} ) | |
317 | ||
318 | Hash with the keys 'r', 'g' and 'b' does the same as previous paragraph, | |
319 | only more declarative. Casing of the keys will be normalised and only | |
320 | the first letter of each key is significant. | |
321 | ||
322 | my $red = Chart::Color->new( r => 255, g => 0, b => 0 ); | |
323 | my $red = Chart::Color->new({r => 255, g => 0, b => 0}); # works too | |
324 | ... Color->new( Red => 255, Green => 0, Blue => 0); # also fine | |
325 | ||
326 | =head2 new( {h => $h, s => $s, l => $l} ) | |
327 | ||
328 | To define a color in HSL space, with values for L</hue>, L</saturation> and | |
329 | L</lightness>, use the following keys, which will be normalized as decribed | |
330 | in previous paragraph. Out of range values will be corrected to the | |
331 | closest value in range. Since L</hue> is a polar coordinate, | |
332 | it will be rotated into range, e.g. 361 = 1. | |
333 | ||
334 | my $red = Chart::Color->new( h => 0, s => 100, b => 50 ); | |
335 | my $red = Chart::Color->new({h => 0, s => 100, b => 50}); # good too | |
336 | ... ->new( Hue => 0, Saturation => 100, Lightness => 50 ); # also fine | |
337 | ||
338 | ||
339 | =head1 GETTER / ATTRIBUTES | |
340 | ||
341 | are all read only methods - giving access to different parts of the | |
342 | objects data. | |
343 | ||
344 | =head2 name | |
345 | ||
346 | Name of the color in the X11 or HTML (SVG) standard or the Pantone report. | |
347 | The name will be found and filled in, even when the object is created | |
348 | with RGB or HSL values. If the color is not found in any of the mentioned | |
349 | standards, it returns an empty string. All names are at: L<Chart::Color::Constant/NAMES> | |
350 | ||
351 | =head2 string | |
352 | ||
353 | String to reproduce color object by: Chart::Color->new (eval $string). | |
354 | It is either the name (if color has one) or the stringified triplet: | |
355 | "[ $red, $green, $blue ]". | |
356 | ||
357 | =head2 red | |
358 | ||
359 | Integer between 0 .. 255 describing the red portion in RGB space. | |
360 | ||
361 | =head2 green | |
362 | ||
363 | Integer between 0 .. 255 describing the green portion in RGB space. | |
364 | ||
365 | =head2 blue | |
366 | ||
367 | Integer between 0 .. 255 describing the blue portion in RGB space. | |
368 | ||
369 | =head2 rgb | |
370 | ||
371 | Three values of red, green and blue (see above). | |
372 | ||
373 | =head2 rgb_hex | |
374 | ||
375 | String starting with '#', followed by six hexadecimal figures. | |
376 | Two digits for each of red, green and blue value - the format used in CSS. | |
377 | ||
378 | =head2 hue | |
379 | ||
380 | Integer between 0 .. 359 describing the angle (in degrees) of the | |
381 | circular dimension in HSL space named hue. | |
382 | 0 approximates red, 30 - orange, 60 - yellow, 120 - green, 180 - cyan, | |
383 | 240 - blue, 270 - violet, 300 - magenta, 330 - pink. | |
384 | 0 and 360 point to the same coordinate, but this module only deals with 0. | |
385 | ||
386 | =head2 saturation | |
387 | ||
388 | Integer between 0 .. 100 describing percentage of saturation in HSL space. | |
389 | 0 is grey and 100 the most colorful (except when lightness is 0 or 100). | |
390 | ||
391 | =head2 lightness | |
392 | ||
393 | Integer between 0 .. 100 describing percentage of lightness in HSL space. | |
394 | 0 is always black, 100 is always white and 50 the most colorful | |
395 | (depending on hue value) (or grey - if saturation = 0). | |
396 | ||
397 | =head2 hsl | |
398 | ||
399 | Three values of hue, saturation and lightness (see above). | |
400 | ||
401 | =head1 METHODS | |
402 | ||
403 | create new, related color (objects) or compute similarity of colors | |
404 | ||
405 | =head2 distance_to | |
406 | ||
407 | A number that measures the distance (difference) between two colors: | |
408 | 1. the calling object (C1) and 2. a provided first argument C2 - | |
409 | color object or scalar data that is acceptable by new method : | |
410 | name or #hex or [$r, $g, $b] or {...} (see chapter L<CONSTRUCTOR>). | |
411 | ||
412 | If no second argument is provided, than the difference is the Euclidean | |
413 | distance in cylindric HSL space. If second argument is 'rgb' or 'RGB', | |
414 | then its the Euclidean distance in RGB space. But als subspaces of both | |
415 | are possible, as r, g, b, rg, rb, gb, h, s, l, hs, hl, and sl. | |
416 | ||
417 | my $d = $blue->distance_to( 'lapisblue' ); # how close to lapis color? | |
418 | # how different is my blue value to airy_blue | |
419 | $d = $blue->distance_to( 'airyblue', 'Blue'); # same amount of blue? | |
420 | $d = $color->distance_to( $c2, 'Hue' ); # same hue ? | |
421 | $d = $color->distance_to( [10, 32, 112 ], 'rgb' ); | |
422 | $d = $color->distance_to( { Hue => 222, Sat => 23, Light => 12 } ); | |
423 | ||
424 | =head2 add | |
425 | ||
426 | Create a Chart::Color object, by adding any RGB or HSL values to current | |
427 | color. (Same rules apply for key names as in new - values can be negative.) | |
428 | RGB and HSL can be combined, but please note that RGB are applied first. | |
429 | ||
430 | If the first argument is a Chart::Color object, than RGB values will be added. | |
431 | In that case an optional second argument is a factor (default = 1), | |
432 | by which the RGB values will be multiplied before being added. Negative | |
433 | values of that factor lead to darkening of result colors, but its not | |
434 | subtractive color mixing, since this module does not support CMY color | |
435 | space. All RGB operations follow the logic of additive mixing, and the | |
436 | result will be rounded (trimmed), to keep it inside the defined RGB space. | |
437 | ||
438 | my $blue = Chart::Color->new('blue'); | |
439 | my $darkblue = $blue->add( Lightness => -25 ); | |
440 | my $blue2 = $blue->add( blue => 10 ); | |
441 | $blue->distance( $blue2 ); # == 0, can't get bluer than blue | |
442 | my $color = $blue->add( $c2, -1.2 ); # subtract color c2 with factor 1.2 | |
443 | ||
444 | =head2 blend_with | |
445 | ||
446 | Create Chart::Color object, that is the average of two colors in HSL space: | |
447 | 1. the calling object (C1) and 2. a provided argument C2 (object or a | |
448 | refrence to data that is acceptable definition). | |
449 | ||
450 | The second argument is the blend ratio, which defaults to 0.5 ( 1:1 ). | |
451 | 0 represents here C1 and 1 C2. Numbers below 0 and above 1 are possible, | |
452 | and will be applied, as long the result is inside the finite HSL space. | |
453 | There is a slight overlap with the add method which mostly operates in | |
454 | RGB (unless told so), while this method always operates in HSL space. | |
455 | ||
456 | my $c = $color->blend_with( Chart::Color->new('silver') ); | |
457 | $color->blend_with( 'silver' ); # same thing | |
458 | $color->blend_with( [192, 192, 192] ); # still same | |
459 | my $difference = $color->blend_with( $c2, -1 ); | |
460 | ||
461 | ||
462 | =head2 gradient_to | |
463 | ||
464 | Creates a gradient (a list of colors that build a transition) between | |
465 | current (C1) and a second, given color (C2). | |
466 | ||
467 | The first argument is C2. Either as an Chart::Color object or a | |
468 | scalar (name, hex or reference), which is acceptable to the method new. | |
469 | ||
470 | Second argument is the number $n of colors, which make up the gradient | |
471 | (including C1 and C2). It defaults to 3. These 3 colors C1, C2 and a | |
472 | color in between, which is the same as the result of method blend_with. | |
473 | ||
474 | Third argument is also a positive number $p, which defaults to one. | |
475 | It defines the dynamics of the transition between the two colors. | |
476 | If $p == 1 you get a linear transition - meaning the distance in HSL | |
477 | space (distance_hsl) is equal from one color to the next. If $p != 1, | |
478 | the formula $n ** $p starts to create a parabola function, which defines | |
479 | a none linear mapping. For values $n > 1 the transition starts by sticking | |
480 | to C1 and slowly getting faster and faster toward C2. Values $n < 1 do | |
481 | the opposite: starting by moving fastest from C1 to C2 (big distances) | |
482 | and becoming slower and slower. | |
483 | ||
484 | my @colors = $c->gradient_to( $grey, 5 ); # we turn to grey | |
485 | @colors = $c1->gradient_to( [14,10,222], 10, 3 ); # none linear gradient | |
486 | ||
487 | =head2 complementary | |
488 | ||
489 | Creates a set of complementary colors. | |
490 | It accepts 3 numerical arguments: n, delta_S and delta_L. | |
491 | ||
492 | Imagine an horizontal circle in HSL space, whith a center in the (grey) | |
493 | center column. The saturation and lightness of all colors on that | |
494 | circle is the same, they differ only in hue. The color of the current | |
495 | color object ($self a.k.a C1) lies on that circle as well as C2, | |
496 | which is 180 degrees (half the circumference) apposed to C1. | |
497 | ||
498 | This circle will be divided in $n (first argument) equal partitions, | |
499 | creating $n equally distanced colors. All of them will be returned, | |
500 | as objects, starting with C1. However, when $n is set to 1 (default), | |
501 | the result is only C2, which is THE complementary color to C1. | |
502 | ||
503 | The second argument moves C2 along the S axis (both directions), | |
504 | so that the center of the circle is no longer in the HSL middle column | |
505 | and the complementary colors differ in saturation. (C1 stays unmoved. ) | |
506 | ||
507 | The third argument moves C2 along the L axis (vertical), which gives the | |
508 | circle a tilt, so that the complementary colors will differ in lightness. | |
509 | ||
510 | my @colors = $c->complementary( 3, +20, -10 ); | |
511 | ||
512 | =head1 COPYRIGHT & LICENSE | |
513 | ||
514 | Copyright 2022 Herbert Breunung. | |
515 | ||
516 | This program is free software; you can redistribute it and/or modify it | |
517 | under same terms as Perl itself. | |
518 | ||
519 | =head1 AUTHOR | |
520 | ||
521 | Herbert Breunung, <lichtkind@cpan.org> | |
522 | ||
523 | =cut | |
524 |
3 | 3 | |
4 | 4 | package Chart::Composite; |
5 | 5 | our @ISA = qw(Chart::Base); |
6 | our $VERSION = 'v2.403.7'; | |
6 | our $VERSION = 'v2.403.8'; | |
7 | 7 | |
8 | 8 | use Chart::Base; |
9 | 9 | use GD; |
3 | 3 | use v5.12; |
4 | 4 | |
5 | 5 | package Chart::Constants; |
6 | our $VERSION = 'v2.403.7'; | |
6 | our $VERSION = 'v2.403.8'; | |
7 | 7 | |
8 | 8 | use constant PI => 4 * atan2( 1, 1 ); |
9 | 9 |
4 | 4 | |
5 | 5 | package Chart::Direction; |
6 | 6 | our @ISA = qw(Chart::Base); |
7 | our $VERSION = 'v2.403.7'; | |
7 | our $VERSION = 'v2.403.8'; | |
8 | 8 | |
9 | 9 | use Chart::Base; |
10 | 10 | use GD; |
5 | 5 | |
6 | 6 | package Chart::ErrorBars; |
7 | 7 | our @ISA = qw(Chart::Base); |
8 | our $VERSION = 'v2.403.7'; | |
8 | our $VERSION = 'v2.403.8'; | |
9 | 9 | |
10 | 10 | use Chart::Base; |
11 | 11 | use GD; |
2 | 2 | |
3 | 3 | package Chart::HorizontalBars; |
4 | 4 | our @ISA = qw(Chart::Base); |
5 | our $VERSION = 'v2.403.7'; | |
5 | our $VERSION = 'v2.403.8'; | |
6 | 6 | |
7 | 7 | use Chart::Base; |
8 | 8 | use GD; |
4 | 4 | |
5 | 5 | package Chart::Lines; |
6 | 6 | our @ISA = qw(Chart::Base); |
7 | our $VERSION = 'v2.403.7'; | |
7 | our $VERSION = 'v2.403.8'; | |
8 | 8 | |
9 | 9 | use Chart::Base; |
10 | 10 | use GD; |
7 | 7 | |
8 | 8 | package Chart::LinesPoints; |
9 | 9 | our @ISA = qw(Chart::Base); |
10 | our $VERSION = 'v2.403.7'; | |
10 | our $VERSION = 'v2.403.8'; | |
11 | 11 | |
12 | 12 | use Chart::Base; |
13 | 13 | use GD; |
55 | 55 | |
56 | 56 | names: 'blue' |
57 | 57 | |
58 | All names are tabulated visually and by name under L<Chart::Color::Constant/NAMES>. | |
58 | All names are tabulated visually and by name under L<Chart::Property::DataType::Color::Constant/NAMES>. | |
59 | 59 | You can also define a color with integer values in the RGB or HSL space. |
60 | 60 | Acceptable ranges are for RGB: 3x 0..255 and for HSL: 0..359, 2 x 0..100. |
61 | 61 | |
65 | 65 | HSL hashes: { H => 240, S => 100, L => 50 } |
66 | 66 | HSL hashes: { hue => 240, saturation => 100, lightness => 50 } |
67 | 67 | |
68 | Detailed explanation and even more options you find under L<Chart::Color>. | |
68 | Detailed explanation and even more options you find under L<Graphics::Toolkit::Color>. | |
69 | 69 | |
70 | 70 | =head2 font |
71 | 71 | |
826 | 826 | |
827 | 827 | =head1 AUTHOR |
828 | 828 | |
829 | David Bonner, <chartgrp@web.de> | |
829 | David Bonner, Chart Group, | |
830 | 830 | |
831 | 831 | Herbert Breunung, <lichtkind@cpan.org> |
832 | 832 |
150 | 150 | my $g = Chart::Direction->new( 500, 500 ); |
151 | 151 | |
152 | 152 | $g->add_dataset( 210, 220, 200, 215, 225, 200 ); |
153 | $g->add_dataset( 30, 40, 20, 35, 45, 20 ); | |
153 | $g->add_dataset( 30, 40, 20, 35, 45, 20 ); | |
154 | 154 | |
155 | 155 | $g->add_dataset( 30, 40, 20, 35, 45, 20 ); |
156 | 156 | $g->add_dataset( 30, 40, 20, 35, 45, 20 ); |
157 | 157 | |
158 | 158 | $g->add_dataset( 120, 130, 110, 125, 135, 110 ); |
159 | $g->add_dataset( 30, 40, 20, 35, 45, 20 ); | |
159 | $g->add_dataset( 30, 40, 20, 35, 45, 20 ); | |
160 | 160 | |
161 | 161 | $g->add_dataset( 300, 310, 290, 305, 315, 290 ); |
162 | $g->add_dataset( 30, 40, 20, 35, 45, 20 ); | |
162 | $g->add_dataset( 30, 40, 20, 35, 45, 20 ); | |
163 | 163 | |
164 | 164 | $g->set( |
165 | 165 | title => 'Direction Demo', |
201 | 201 | |
202 | 202 | use Chart::ErrorBars; |
203 | 203 | |
204 | my $g = Chart::ErrorBars->new(); | |
204 | my $g = Chart::ErrorBars->new( 500, 400 ); | |
205 | 205 | $g->add_dataset(qw(1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.1 2.2 2.3 2.4 2.5)); |
206 | $g->add_dataset(qw(1 1.1 1.2 1.1 1.14 1.15 1.26 1.2 1.1 1.19 1.2 1.4 1.6 2.0 2.5 3.1)); | |
206 | $g->add_dataset(qw(1 1.1 1.2 1.1 1.14 1.15 1.26 1.2 1.1 1.19 1.2 1.4 1.6 2.0 2.5 3.1)); | |
207 | 207 | $g->add_dataset(qw(0.4 0.1 0.2 0.1 0.14 0.15 0.26 0.27 0.1 0.19 0.2 0.1 0.1 0.2 0.1 0.3)); |
208 | 208 | $g->add_dataset(qw(0.2 0.11 0.12 0.11 0.2 0.3 0.12 0.27 0.11 0.3 0.2 0.2 0.2 0.1 0.1 0.2)); |
209 | 209 | $g->set( |
260 | 260 | $g->png("hbars.png"); |
261 | 261 | |
262 | 262 | |
263 | =head1 Lines | |
263 | =head2 Lines | |
264 | 264 | |
265 | 265 | =for HTML <p> |
266 | 266 | <img src="https://raw.githubusercontent.com/lichtkind/Chart/main/dev/example/manual/lines.png" alt="xy chart with lines"> |
646 | 646 | |
647 | 647 | =head1 AUTHOR |
648 | 648 | |
649 | David Bonner, <chartgrp@web.de> | |
649 | David Bonner, | |
650 | 650 | |
651 | 651 | Herbert Breunung, <lichtkind@cpan.org> |
652 | 652 |
55 | 55 | |
56 | 56 | =head1 AUTHOR |
57 | 57 | |
58 | David Bonner, <chartgrp@web.de> | |
58 | David Bonner, Chart Group, | |
59 | 59 | |
60 | 60 | Herbert Breunung, <lichtkind@cpan.org> |
61 | 61 |
23 | 23 | |
24 | 24 | package Chart::Mountain; |
25 | 25 | our @ISA = qw(Chart::Base); |
26 | our $VERSION = 'v2.403.7'; | |
26 | our $VERSION = 'v2.403.8'; | |
27 | 27 | |
28 | 28 | use Chart::Base; |
29 | 29 | use GD; |
1 | 1 | |
2 | 2 | package Chart::Pareto; |
3 | 3 | our @ISA = qw(Chart::Base); |
4 | our $VERSION = 'v2.403.7'; | |
4 | our $VERSION = 'v2.403.8'; | |
5 | 5 | |
6 | 6 | use Chart::Base; |
7 | 7 | use GD; |
4 | 4 | |
5 | 5 | package Chart::Pie; |
6 | 6 | our @ISA = qw(Chart::Base); |
7 | our $VERSION = 'v2.403.7'; | |
7 | our $VERSION = 'v2.403.8'; | |
8 | 8 | |
9 | 9 | use Carp; |
10 | 10 | use GD; |
4 | 4 | |
5 | 5 | package Chart::Points; |
6 | 6 | our @ISA = qw(Chart::Base); |
7 | our $VERSION = 'v2.403.7'; | |
7 | our $VERSION = 'v2.403.8'; | |
8 | 8 | |
9 | 9 | use Carp; |
10 | 10 | use GD; |
0 | ||
1 | # Chart::Color: read only color holding object | |
2 | # with methods for relation, mixing and transitions | |
3 | ||
4 | use v5.12; | |
5 | ||
6 | package Chart::Property::DataType::Color; | |
7 | our $VERSION = 'v2.403.8'; | |
8 | ||
9 | use base qw(Graphics::Toolkit::Color); | |
10 | ||
11 | 1; | |
12 | __END__ | |
13 | ||
14 | =pod | |
15 | ||
16 | moved to L<Graphics::Toolkit::Color> | |
17 | ||
18 | =cut |
3 | 3 | use v5.12; |
4 | 4 | |
5 | 5 | package Chart::Property::DataType::Font; |
6 | our $VERSION = 'v2.403.7'; | |
6 | our $VERSION = 'v2.403.8'; | |
7 | 7 | |
8 | 8 | use Carp; |
9 | 9 |
3 | 3 | use v5.12; |
4 | 4 | |
5 | 5 | package Chart::Property; |
6 | our $VERSION = 'v2.403.7'; | |
6 | our $VERSION = 'v2.403.8'; | |
7 | 7 | |
8 | 8 | use Carp; |
9 | 9 |
17 | 17 | |
18 | 18 | package Chart::Split; |
19 | 19 | our @ISA = qw(Chart::Base); |
20 | our $VERSION = 'v2.403.7'; | |
20 | our $VERSION = 'v2.403.8'; | |
21 | 21 | |
22 | 22 | use Chart::Base; |
23 | 23 | use GD; |
1 | 1 | |
2 | 2 | package Chart::StackedBars; |
3 | 3 | our @ISA = qw(Chart::Base); |
4 | our $VERSION = 'v2.403.7'; | |
4 | our $VERSION = 'v2.403.8'; | |
5 | 5 | |
6 | 6 | use Chart::Base; |
7 | 7 | use GD; |
0 | 0 | use v5.12; |
1 | 1 | |
2 | 2 | package Chart; |
3 | our $VERSION = 'v2.403.7'; | |
3 | our $VERSION = 'v2.403.8'; | |
4 | 4 | |
5 | 5 | use Chart::Points; |
6 | 6 | use Chart::Lines; |
0 | #!/usr/bin/perl | |
1 | ||
2 | use v5.12; | |
3 | use warnings; | |
4 | use Test::More tests => 108; | |
5 | use Test::Warn; | |
6 | ||
7 | BEGIN { unshift @INC, 'lib', '../lib'} | |
8 | my $module = 'Chart::Color::Value'; | |
9 | ||
10 | eval "use $module"; | |
11 | is( not($@), 1, 'could load the module'); | |
12 | ||
13 | my $chk_rgb = \&Chart::Color::Value::check_rgb; | |
14 | my $chk_hsl = \&Chart::Color::Value::check_hsl; | |
15 | my $tr_rgb = \&Chart::Color::Value::trim_rgb; | |
16 | my $tr_hsl = \&Chart::Color::Value::trim_hsl; | |
17 | my $d_rgb = \&Chart::Color::Value::distance_rgb; | |
18 | my $d_hsl = \&Chart::Color::Value::distance_hsl; | |
19 | my $rgb2h = \&Chart::Color::Value::hex_from_rgb; | |
20 | ||
21 | ||
22 | ok( !$chk_rgb->(0,0,0), 'check rgb values works on lower bound values'); | |
23 | ok( !$chk_rgb->(255,255,255), 'check rgb values works on upper bound values'); | |
24 | warning_like {$chk_rgb->(0,0)} {carped => qr/exactly 3/}, "check rgb got too few values"; | |
25 | warning_like {$chk_rgb->(0,0,0,0)} {carped => qr/exactly 3/}, "check rgb got too many values"; | |
26 | warning_like {$chk_rgb->(-1, 0,0)} {carped => qr/red value/}, "red value is too small"; | |
27 | warning_like {$chk_rgb->(0.5, 0,0)} {carped => qr/red value/}, "red value is not integer"; | |
28 | warning_like {$chk_rgb->(256, 0,0)} {carped => qr/red value/}, "red value is too big"; | |
29 | warning_like {$chk_rgb->(0, -1, 0)} {carped => qr/green value/}, "green value is too small"; | |
30 | warning_like {$chk_rgb->(0, 0.5, 0)} {carped => qr/green value/}, "green value is not integer"; | |
31 | warning_like {$chk_rgb->(0, 256,0)} {carped => qr/green value/}, "green value is too big"; | |
32 | warning_like {$chk_rgb->(0,0, -1 )} {carped => qr/blue value/}, "blue value is too small"; | |
33 | warning_like {$chk_rgb->(0,0, 0.5 )} {carped => qr/blue value/}, "blue value is not integer"; | |
34 | warning_like {$chk_rgb->(0,0, 256)} {carped => qr/blue value/}, "blue value is too big"; | |
35 | ||
36 | ok( !$chk_hsl->(0,0,0), 'check hsl values works on lower bound values'); | |
37 | ok( !$chk_hsl->(359,100,100), 'check hsl values works on upper bound values'); | |
38 | warning_like {$chk_hsl->(0,0)} {carped => qr/exactly 3/}, "check rgb got too few values"; | |
39 | warning_like {$chk_hsl->(0,0,0,0)} {carped => qr/exactly 3/}, "check rgb got too many values"; | |
40 | warning_like {$chk_hsl->(-1, 0,0)} {carped => qr/hue value/}, "hue value is too small"; | |
41 | warning_like {$chk_hsl->(0.5, 0,0)} {carped => qr/hue value/}, "hue value is not integer"; | |
42 | warning_like {$chk_hsl->(360, 0,0)} {carped => qr/hue value/}, "hue value is too big"; | |
43 | warning_like {$chk_hsl->(0, -1, 0)} {carped => qr/saturation value/}, "saturation value is too small"; | |
44 | warning_like {$chk_hsl->(0, 0.5, 0)} {carped => qr/saturation value/}, "saturation value is not integer"; | |
45 | warning_like {$chk_hsl->(0, 101,0)} {carped => qr/saturation value/}, "saturation value is too big"; | |
46 | warning_like {$chk_hsl->(0,0, -1 )} {carped => qr/lightness value/}, "lightness value is too small"; | |
47 | warning_like {$chk_hsl->(0,0, 0.5 )} {carped => qr/lightness value/}, "lightness value is not integer"; | |
48 | warning_like {$chk_hsl->(0,0, 101)} {carped => qr/lightness value/}, "lightness value is too big"; | |
49 | ||
50 | ||
51 | ||
52 | my @rgb = $tr_rgb->(); | |
53 | is( int @rgb, 3, 'default color is set'); | |
54 | is( $rgb[0], 0, 'default color is black (R) no args'); | |
55 | is( $rgb[1], 0, 'default color is black (G) no args'); | |
56 | is( $rgb[2], 0, 'default color is black (B) no args'); | |
57 | @rgb = $tr_rgb->(1,2); | |
58 | is( $rgb[0], 0, 'default color is black (R) too few args'); | |
59 | is( $rgb[1], 0, 'default color is black (G) too few args'); | |
60 | is( $rgb[2], 0, 'default color is black (B) too few args'); | |
61 | @rgb = $tr_rgb->(1,2,3,4); | |
62 | is( $rgb[0], 0, 'default color is black (R) too many args'); | |
63 | is( $rgb[1], 0, 'default color is black (G) too many args'); | |
64 | is( $rgb[2], 0, 'default color is black (B) too many args'); | |
65 | @rgb = $tr_rgb->(-1,-1,-1); | |
66 | is( int @rgb, 3, 'color is trimmed up'); | |
67 | is( $rgb[0], 0, 'too low red value is trimmed up'); | |
68 | is( $rgb[1], 0, 'too low green value is trimmed up'); | |
69 | is( $rgb[2], 0, 'too low blue value is trimmed up'); | |
70 | @rgb = $tr_rgb->(256, 256, 256); | |
71 | is( int @rgb, 3, 'color is trimmed up'); | |
72 | is( $rgb[0], 255, 'too high red value is trimmed down'); | |
73 | is( $rgb[1], 255, 'too high green value is trimmed down'); | |
74 | is( $rgb[2], 255, 'too high blue value is trimmed down'); | |
75 | ||
76 | my @hsl = $tr_hsl->(); | |
77 | is( int @hsl, 3, 'default color is set'); | |
78 | is( $hsl[0], 0, 'default color is black (H) no args'); | |
79 | is( $hsl[1], 0, 'default color is black (S) no args'); | |
80 | is( $hsl[2], 0, 'default color is black (L) no args'); | |
81 | @hsl = $tr_hsl->(1,2); | |
82 | is( $hsl[0], 0, 'default color is black (H) too few args'); | |
83 | is( $hsl[1], 0, 'default color is black (S) too few args'); | |
84 | is( $hsl[2], 0, 'default color is black (L) too few args'); | |
85 | @hsl = $tr_hsl->(1,2,3,4); | |
86 | is( $hsl[0], 0, 'default color is black (H) too many args'); | |
87 | is( $hsl[1], 0, 'default color is black (S) too many args'); | |
88 | is( $hsl[2], 0, 'default color is black (L) too many args');; | |
89 | @hsl = $tr_hsl->(-1,-1,-1); | |
90 | is( int @rgb, 3, 'color is trimmed up'); | |
91 | is( $hsl[0], 359, 'too low hue value is rotated up'); | |
92 | is( $hsl[1], 0, 'too low green value is trimmed up'); | |
93 | is( $hsl[2], 0, 'too low blue value is trimmed up'); | |
94 | @hsl = $tr_hsl->(360, 101, 101); | |
95 | is( int @rgb, 3, 'color is trimmed up'); | |
96 | is( $hsl[0], 0, 'too high hue value is rotated down'); | |
97 | is( $hsl[1], 100, 'too high saturation value is trimmed down'); | |
98 | is( $hsl[2], 100, 'too high lightness value is trimmed down'); | |
99 | ||
100 | ||
101 | warning_like {Chart::Color::Value::hsl_from_rgb(1,1,1,1)} {carped => qr/3 positive integer/}, | |
102 | "need 3 values rgb to convert color from rgb to hsl"; | |
103 | warning_like {Chart::Color::Value::hsl_from_rgb(1,1)} {carped => qr/3 positive integer/}, | |
104 | "need 3 values rgb to convert color from rgb to hsl"; | |
105 | warning_like {Chart::Color::Value::hsl_from_rgb(1,1,-1)} {carped => qr/blue value/}, | |
106 | "blue value is too small for conversion"; | |
107 | warning_like {Chart::Color::Value::hsl_from_rgb(256,1,0)} {carped => qr/red value/}, | |
108 | "red value is too large for conversion"; | |
109 | warning_like {Chart::Color::Value::rgb_from_hsl(1,1)} {carped => qr/3 positive integer/}, | |
110 | "need 3 values rgb to convert color from rgb to hsl"; | |
111 | ||
112 | @hsl = Chart::Color::Value::hsl_from_rgb(127, 127, 127); | |
113 | is( int @hsl, 3, 'converted color grey has hsl values'); | |
114 | is( $hsl[0], 0, 'converted color grey has computed right hue value'); | |
115 | is( $hsl[1], 0, 'converted color grey has computed right saturation'); | |
116 | is( $hsl[2], 50, 'converted color grey has computed right lightness'); | |
117 | ||
118 | @rgb = Chart::Color::Value::rgb_from_hsl(0, 0, 50); | |
119 | is( int @rgb, 3, 'converted back color grey has rgb values'); | |
120 | is( $rgb[0], 128, 'converted back color grey has right red value'); | |
121 | is( $rgb[1], 128, 'converted back color grey has right green value'); | |
122 | is( $rgb[2], 128, 'converted back color grey has right blue value'); | |
123 | ||
124 | warning_like {$d_rgb->()} {carped => qr/two triplets/},"can't get distance without rgb values"; | |
125 | warning_like {$d_rgb->( [1,1,1],[1,1,1],[1,1,1])} {carped => qr/two triplets/},'too many array arg'; | |
126 | warning_like {$d_rgb->( [1,2],[1,2,3])} {carped => qr/two triplets/},'first color is missing a value'; | |
127 | warning_like {$d_rgb->( [1,2,3],[2,3])} {carped => qr/two triplets/},'second color is missing a value'; | |
128 | warning_like {$d_rgb->( [-1,2,3],[1,2,3])} {carped => qr/red value/}, 'first red value is too small'; | |
129 | warning_like {$d_rgb->( [1,2,3],[2,256,3])} {carped => qr/green value/}, 'second green value is too large'; | |
130 | warning_like {$d_rgb->( [1,2,-3],[2,25,3])} {carped => qr/blue value/}, 'first blue value is too large'; | |
131 | warning_like {$d_hsl->( []) } {carped => qr/two triplets/},"can't get distance without hsl values"; | |
132 | warning_like {$d_hsl->( [1,1,1],[1,1,1],[1,1,1])} {carped => qr/two triplets/},'too many array arg'; | |
133 | warning_like {$d_hsl->( [1,2],[1,2,3])} {carped => qr/two triplets/},'first color is missing a value'; | |
134 | warning_like {$d_hsl->( [1,2,3],[2,3])} {carped => qr/two triplets/},'second color is missing a value'; | |
135 | warning_like {$d_hsl->( [-1,2,3],[1,2,3])} {carped => qr/hue value/}, 'first hue value is too small'; | |
136 | warning_like {$d_hsl->( [1,2,3],[360,2,3])} {carped => qr/hue value/}, 'second hue value is too large'; | |
137 | warning_like {$d_hsl->( [1,-1,3],[2,10,3])} {carped => qr/saturation value/},'first saturation value is too small'; | |
138 | warning_like {$d_hsl->( [1,2,3],[2,101,3])} {carped => qr/saturation value/},'second saturation value is too large'; | |
139 | warning_like {$d_hsl->( [1,1,-1],[2,10,3])} {carped => qr/lightness value/}, 'first lightness value is too small'; | |
140 | warning_like {$d_hsl->( [1,2,3],[2,1,101])} {carped => qr/lightness value/}, 'second lightness value is too large'; | |
141 | ||
142 | is( Chart::Color::Value::distance_rgb([1, 2, 3], [ 2, 6, 11]), 9, 'compute rgb distance'); | |
143 | is( Chart::Color::Value::distance_hsl([1, 2, 3], [ 2, 6, 11]), 9, 'compute hsl distance'); | |
144 | is( Chart::Color::Value::distance_hsl([0, 2, 3], [359, 6, 11]), 9, 'compute hsl distance (test circular property of hsl)'); | |
145 | ||
146 | ||
147 | is( $rgb2h->(0,0,0), '#000000', 'converted black from rgb to hex'); | |
148 | is( uc $rgb2h->(255,255,255), '#FFFFFF', 'converted white from rgb to hex'); | |
149 | is( uc $rgb2h->( 10, 20, 30), '#0A141E', 'converted random color from rgb to hex'); | |
150 | ||
151 | @rgb = Chart::Color::Value::rgb_from_hex('#000000'); | |
152 | is( $rgb[0], 0, 'converted black from hex to RGB red is correct'); | |
153 | is( $rgb[1], 0, 'converted black from hex to RGB green is correct'); | |
154 | is( $rgb[2], 0, 'converted black from hex to RGB blue is correct'); | |
155 | ||
156 | @rgb = Chart::Color::Value::rgb_from_hex('#FFF'); | |
157 | is( $rgb[0], 255, 'converted white (short form) from hex to RGB red is correct'); | |
158 | is( $rgb[1], 255, 'converted white (short form) from hex to RGB green is correct'); | |
159 | is( $rgb[2], 255, 'converted white (short form) from hex to RGB blue is correct'); | |
160 | ||
161 | @rgb = Chart::Color::Value::rgb_from_hex('#0a141e'); | |
162 | is( $rgb[0], 10, 'converted random color (lower case) from hex to RGB red is correct'); | |
163 | is( $rgb[1], 20, 'converted random color (lower case) from hex to RGB green is correct'); | |
164 | is( $rgb[2], 30, 'converted random color (lower case) from hex to RGB blue is correct'); | |
165 | ||
166 | ||
167 | ||
168 | exit 0; |
0 | #!/usr/bin/perl | |
1 | ||
2 | use v5.12; | |
3 | use warnings; | |
4 | use Test::More tests => 57; | |
5 | use Test::Warn; | |
6 | ||
7 | BEGIN { unshift @INC, 'lib', '../lib'} | |
8 | my $module = 'Chart::Color::Constant'; | |
9 | ||
10 | eval "use $module"; | |
11 | is( not($@), 1, 'could load the module'); | |
12 | ||
13 | my @names = Chart::Color::Constant::all_names(); | |
14 | is( @names > 700, 1, 'get a large list of names, all_names seems to working'); | |
15 | ||
16 | my $add_rgb = \&Chart::Color::Constant::add_rgb; | |
17 | my $add_hsl = \&Chart::Color::Constant::add_hsl; | |
18 | my $taken = \&Chart::Color::Constant::name_taken; | |
19 | my $get_name_rgb = \&Chart::Color::Constant::name_from_rgb; | |
20 | my $get_name_hsl = \&Chart::Color::Constant::name_from_hsl; | |
21 | my $get_name_range = \&Chart::Color::Constant::names_in_hsl_range; | |
22 | ||
23 | warning_like {$add_rgb->()} {carped => qr/missing first arg/}, "can't get color without name"; | |
24 | warning_like {$add_rgb->( 'one',1,1)} {carped => qr/need exactly 3/},'not enough args to add color'; | |
25 | warning_like {$add_rgb->( 'one', 0, -1, 25)} {carped => qr/green/}, 'too small green value got cought'; | |
26 | warning_like {$add_rgb->( 'one', 0, 1, 256)} {carped => qr/blue/}, 'too large blue value got cought'; | |
27 | warning_like {$add_rgb->( 'white', 0, 3, 22 )} {carped => qr/already/}, 'got cought overwriting white'; | |
28 | ||
29 | is( $taken->('one'), '', 'there is not color named "one"' ); | |
30 | is( ref $add_rgb->('one', 1, 2, 3 ), 'ARRAY', 'could add color to store'); | |
31 | is( $get_name_rgb->( 1, 2, 3 ), 'one', 'retrieve added color' ); | |
32 | is( $taken->('one'), 1, 'there is now a color named "one"' ); | |
33 | is( $taken->('One'), 1, 'even there with different spelling'); | |
34 | is( ref $add_hsl->('lucky', 0,100, 50),'ARRAY', 'added red under different name'); | |
35 | is( ref $add_hsl->('blob', 14, 10, 50),'ARRAY', 'added color by hsl definition'); | |
36 | ||
37 | is( $get_name_rgb->( 255 ,255, 255 ), 'white', 'could get a color def'); | |
38 | is( scalar $get_name_rgb->( 255, 215, 0 ), 'gold', 'selects shorter name: gold instead of gold1'); | |
39 | is( scalar $get_name_rgb->( [255, 215, 0]),'gold', 'array ref arg format works too'); | |
40 | is( scalar $get_name_rgb->( 255, 0, 0 ), 'red', 'selects shorter name red instead of inserted lucky'); | |
41 | is( $get_name_hsl->( 0, 100, 50 ), 'red', 'found red by hsl'); | |
42 | is( $get_name_hsl->( 14, 10, 50 ), 'blob', 'found inserted color by hsl'); | |
43 | ||
44 | my @rgb = Chart::Color::Constant::rgb_from_name('white'); | |
45 | my @hsl = Chart::Color::Constant::hsl_from_name('white'); | |
46 | is( int @rgb, 3, 'white has 3 rgb values'); | |
47 | is( $rgb[0], 255, 'white has full red value'); | |
48 | is( $rgb[1], 255, 'white has full green value'); | |
49 | is( $rgb[2], 255, 'white has full blue value'); | |
50 | is( int @hsl, 3, 'white has 3 hsl values'); | |
51 | is( $hsl[0], 0, 'white has zero hue value'); | |
52 | is( $hsl[1], 0, 'white has zero sat value'); | |
53 | is( $hsl[2], 100, 'white has full light value'); | |
54 | ||
55 | @rgb = Chart::Color::Constant::rgb_from_name('one'); | |
56 | @hsl = Chart::Color::Constant::hsl_from_name('one'); | |
57 | is( int @rgb, 3, 'self defined color has rgb values'); | |
58 | is( $rgb[0], 1, 'self defined color has defined red value'); | |
59 | is( $rgb[1], 2, 'self defined color has defined full green value'); | |
60 | is( $rgb[2], 3, 'self defined color has defined full blue value'); | |
61 | is( int @hsl, 3, 'self defined color has hsl values'); | |
62 | is( $hsl[0], 210, 'self defined color has computed hue value'); | |
63 | is( $hsl[1], 50, 'self defined color has computed saturation'); | |
64 | is( $hsl[2], 1, 'self defined color has computed lightness'); | |
65 | ||
66 | @rgb = Chart::Color::Constant::rgb_from_name('One'); | |
67 | is( int @rgb, 3, 'upper case gets cleaned from color name'); | |
68 | @rgb = Chart::Color::Constant::rgb_from_name('O_ne'); | |
69 | is( int @rgb, 3, 'under score gets cleaned from color name'); | |
70 | ||
71 | warning_like{ $get_name_range->( []) } {carped => qr/two arguments/},"can't get names in range without hsl values"; | |
72 | warning_like{ $get_name_range->( [1,1,1],[1,1,1],[1,1,1])} {carped => qr/two arguments/},'too many array arg'; | |
73 | warning_like{ $get_name_range->( [1,2],[1,2,3])} {carped => qr/first argument/},'range center is missing a value'; | |
74 | warning_like{ $get_name_range->( [1,2,3],[2,3])} {carped => qr/second argument/}, 'tolerances are missing a value'; | |
75 | warning_like{ $get_name_range->( [-1,2,3],[1,2,3])} {carped => qr/hue value/}, 'first value of search center is too small'; | |
76 | warning_like{ $get_name_range->( [360,2,3],[1,2,3])} {carped => qr/hue value/}, 'first value of search center is too large'; | |
77 | warning_like{ $get_name_range->( [1,-1,3],[2,10,3])} {carped => qr/saturation value/}, 'saturation center value is too small'; | |
78 | warning_like{ $get_name_range->( [1,101,3],[2,1,3])} {carped => qr/saturation value/}, 'saturation center value is too large'; | |
79 | warning_like{ $get_name_range->( [1,1,-1],[2,10,3])} {carped => qr/lightness value/}, 'first lightness value is too small'; | |
80 | warning_like{ $get_name_range->( [1,2,101],[2,1,1])} {carped => qr/lightness value/}, 'second lightness value is too large'; | |
81 | ||
82 | @names = $get_name_range->( [0, 0, 100], 0); | |
83 | is( int @names, 1, 'only one color has distance of 0 to white'); | |
84 | is( $names[0], 'white', 'only white has distance of 0 to white'); | |
85 | ||
86 | @names = sort $get_name_range->( [0, 0, 100], 5); | |
87 | is( int @names, 6, '6 colors are in short distance to white'); | |
88 | @names = grep { /whitesmoke/ } @names; | |
89 | is( int @names, 1, 'whitesmoke is near to white'); | |
90 | ||
91 | my @morenames = sort $get_name_range->( [0, 0, 100], 10); | |
92 | is( @names < @morenames, 1, 'bigger radius has to catch more colors'); | |
93 | ||
94 | @names = sort $get_name_range->( [240, 100, 50], [10, 20, 30]); | |
95 | @names = grep { /navy/ } @names; | |
96 | is( int @names, 1, 'navy is a shade of blue'); | |
97 | ||
98 | @names = sort $get_name_range->( [240, 100, 50], [100, 5, 5]); | |
99 | @names = grep { /aqua/ } @names; | |
100 | is( int @names, 1, 'aqua is a bluish color with high saturation and medium lightness'); | |
101 | ||
102 | @names = sort $get_name_range->( [ 0, 100, 50], [100, 5, 5]); | |
103 | @names = grep { /lightpurple/ } @names; | |
104 | is( int @names, 1, 'purple is near red because hue is circular'); | |
105 | ||
106 | @names = sort $get_name_range->( [ 359, 100, 50], [100, 5, 5]); | |
107 | @names = grep { /chartreuse/ } @names; | |
108 | is( @names > 0, 1, 'chartreuse is near purple because hue is circular'); | |
109 | ||
110 | #say for @names; | |
111 | #say scalar $get_name_hsl->(240, 100, 50); | |
112 | ||
113 | exit 0; | |
114 | ||
115 | __END__ | |
116 | ||
117 | use Memory::Usage; | |
118 | my $mu = Memory::Usage->new(); | |
119 | $mu->record('starting work'); | |
120 | eval "use $module"; | |
121 | $mu->record('after '); | |
122 | eval "use GD;"; | |
123 | $mu->record('GD '); | |
124 | $mu->dump(); |
0 | #!/usr/bin/perl | |
1 | # | |
2 | use v5.12; | |
3 | use warnings; | |
4 | use Test::More tests => 303; | |
5 | use Test::Warn; | |
6 | ||
7 | BEGIN { unshift @INC, 'lib', '../lib'} | |
8 | my $module = 'Chart::Color'; | |
9 | eval "use $module"; | |
10 | is( not( $@), 1, 'could load the module'); | |
11 | ||
12 | ||
13 | warning_like {Chart::Color->new()} {carped => qr/constructor of/}, "need argument to create object"; | |
14 | warning_like {Chart::Color->new('weirdcolorname')} {carped => qr/unknown color/}, "accept only known color names"; | |
15 | warning_like {Chart::Color->new('CHIMNEY:red')} {carped => qr/ not installed/}, "accept only known palletes"; | |
16 | warning_like {Chart::Color->new('#23232') } {carped => qr/hex color definition/}, "hex definition too short"; | |
17 | warning_like {Chart::Color->new('#232321f') } {carped => qr/hex color definition/}, "hex definition too long"; | |
18 | warning_like {Chart::Color->new('#23232g') } {carped => qr/hex color definition/}, "hex definition has forbidden chars"; | |
19 | warning_like {Chart::Color->new('#2322%E') } {carped => qr/hex color definition/}, "hex definition has forbidden chars"; | |
20 | warning_like {Chart::Color->new(1,1)} {carped => qr/constructor of/}, "too few positional args"; | |
21 | warning_like {Chart::Color->new(1,1,1,1,1)} {carped => qr/constructor of/}, "too many positional args"; | |
22 | warning_like {Chart::Color->new([1,1])} {carped => qr/need exactly 3/}, "too few positional args in ref"; | |
23 | warning_like {Chart::Color->new([1,1,1,1])} {carped => qr/need exactly 3/}, "too many positional args in ref"; | |
24 | warning_like {Chart::Color->new({ r=>1, g=>1})} {carped => qr/constructor of/}, "too few named args in ref"; | |
25 | warning_like {Chart::Color->new({r=>1,g=>1,b=>1,h=>1,})} {carped => qr/constructor of/},"too many name args in ref"; | |
26 | warning_like {Chart::Color->new( r=>1)} {carped => qr/constructor of/}, "too few named args"; | |
27 | warning_like {Chart::Color->new(r=>1,g=>1,b=>1,h=>1,a=>1)} {carped => qr/constructor of/}, "too many name args"; | |
28 | warning_like {Chart::Color->new(r=>1,g=>1,h=>1)} {carped => qr/argument keys/}, "don't mix named args"; | |
29 | warning_like {Chart::Color->new(r=>1,g=>1,t=>1)} {carped => qr/argument keys/}, "don't invent named args"; | |
30 | ||
31 | my $red = Chart::Color->new('red'); | |
32 | is( ref $red, $module, 'could create object by name'); | |
33 | is( $red->red, 255, 'named red has correct red component value'); | |
34 | is( $red->green, 0, 'named red has correct green component value'); | |
35 | is( $red->blue, 0, 'named red has correct blue component value'); | |
36 | is( $red->hue, 0, 'named red has correct hue component value'); | |
37 | is( $red->saturation, 100, 'named red has correct saturation component value'); | |
38 | is( $red->lightness, 50, 'named red has correct lightness component value'); | |
39 | is( $red->name, 'red', 'named red has correct name'); | |
40 | is( $red->rgb_hex, '#ff0000', 'named red has correct hex value'); | |
41 | is(($red->rgb)[0], 255, 'named red has correct rgb red component value'); | |
42 | is(($red->rgb)[1], 0, 'named red has correct rgb green component value'); | |
43 | is(($red->rgb)[2], 0, 'named red has correct rgb blue component value'); | |
44 | is(($red->hsl)[0], 0, 'named red has correct hsl hue component value'); | |
45 | is(($red->hsl)[1], 100, 'named red has correct hsl saturation component value'); | |
46 | is(($red->hsl)[2], 50, 'named red has correct hsl lightness component value'); | |
47 | is( $red->string, 'red', 'named red does stringify correctly'); | |
48 | is( Chart::Color->new(15,12,13)->string, '[ 15, 12, 13 ]', 'random color does stringify correctly'); | |
49 | ||
50 | ||
51 | $red = Chart::Color->new('#FF0000'); | |
52 | is( ref $red, $module, 'could create object by hex value'); | |
53 | is( $red->red, 255, 'hex red has correct red component value'); | |
54 | is( $red->green, 0, 'hex red has correct green component value'); | |
55 | is( $red->blue, 0, 'hex red has correct blue component value'); | |
56 | is( $red->hue, 0, 'hex red has correct hue component value'); | |
57 | is( $red->saturation, 100, 'hex red has correct saturation component value'); | |
58 | is( $red->lightness, 50, 'hex red has correct lightness component value'); | |
59 | is( $red->name, 'red', 'hex red has correct name'); | |
60 | is( $red->rgb_hex, '#ff0000', 'hex red has correct hex value'); | |
61 | is(($red->rgb)[0], 255, 'hex red has correct rgb red component value'); | |
62 | is(($red->rgb)[1], 0, 'hex red has correct rgb green component value'); | |
63 | is(($red->rgb)[2], 0, 'hex red has correct rgb blue component value'); | |
64 | is(($red->hsl)[0], 0, 'hex red has correct hsl hue component value'); | |
65 | is(($red->hsl)[1], 100, 'hex red has correct hsl saturation component value'); | |
66 | is(($red->hsl)[2], 50, 'hex red has correct hsl lightness component value'); | |
67 | ||
68 | $red = Chart::Color->new('#f00'); | |
69 | is( ref $red, $module, 'could create object by short hex value'); | |
70 | is( $red->name, 'red', 'short hex red has correct name'); | |
71 | ||
72 | $red = Chart::Color->new(255, 0, 0); | |
73 | is( ref $red, $module, 'could create object by positional RGB'); | |
74 | is( $red->red, 255, 'positional red has correct red component value'); | |
75 | is( $red->green, 0, 'positional red has correct green component value'); | |
76 | is( $red->blue, 0, 'positional red has correct blue component value'); | |
77 | is( $red->hue, 0, 'positional red has correct hue component value'); | |
78 | is( $red->saturation, 100, 'positional red has correct saturation component value'); | |
79 | is( $red->lightness, 50, 'positional red has correct lightness component value'); | |
80 | is( $red->name, 'red', 'positional red has correct name'); | |
81 | is( $red->rgb_hex, '#ff0000', 'positional red has correct hex value'); | |
82 | is(($red->rgb)[0], 255, 'positional red has correct rgb red component value'); | |
83 | is(($red->rgb)[1], 0, 'positional red has correct rgb green component value'); | |
84 | is(($red->rgb)[2], 0, 'positional red has correct rgb blue component value'); | |
85 | is(($red->hsl)[0], 0, 'positional red has correct hsl hue component value'); | |
86 | is(($red->hsl)[1], 100, 'positional red has correct hsl saturation component value'); | |
87 | is(($red->hsl)[2], 50, 'positional red has correct hsl lightness component value'); | |
88 | ||
89 | $red = Chart::Color->new([255, 0, 0]); | |
90 | is( ref $red, $module, 'could create object by RGB array ref'); | |
91 | is( $red->red, 255, 'array ref red has correct red component value'); | |
92 | is( $red->green, 0, 'array ref red has correct green component value'); | |
93 | is( $red->blue, 0, 'array ref red has correct blue component value'); | |
94 | is( $red->hue, 0, 'array ref red has correct hue component value'); | |
95 | is( $red->saturation, 100, 'array ref red has correct saturation component value'); | |
96 | is( $red->lightness, 50, 'array ref red has correct lightness component value'); | |
97 | is( $red->name, 'red', 'array ref red has correct name'); | |
98 | is( $red->rgb_hex, '#ff0000', 'array ref red has correct hex value'); | |
99 | is(($red->rgb)[0], 255, 'array ref red has correct rgb red component value'); | |
100 | is(($red->rgb)[1], 0, 'array ref red has correct rgb green component value'); | |
101 | is(($red->rgb)[2], 0, 'array ref red has correct rgb blue component value'); | |
102 | is(($red->hsl)[0], 0, 'array ref red has correct hsl hue component value'); | |
103 | is(($red->hsl)[1], 100, 'array ref red has correct hsl saturation component value'); | |
104 | is(($red->hsl)[2], 50, 'array ref red has correct hsl lightness component value'); | |
105 | ||
106 | $red = Chart::Color->new(r => 255, g => 0, b => 0); | |
107 | is( ref $red, $module, 'could create object by RGB named args'); | |
108 | is( $red->red, 255, 'named arg red has correct red component value'); | |
109 | is( $red->green, 0, 'named arg red has correct green component value'); | |
110 | is( $red->blue, 0, 'named arg red has correct blue component value'); | |
111 | is( $red->hue, 0, 'named arg red has correct hue component value'); | |
112 | is( $red->saturation, 100, 'named arg red has correct saturation component value'); | |
113 | is( $red->lightness, 50, 'named arg red has correct lightness component value'); | |
114 | is( $red->name, 'red', 'named arg red has correct name'); | |
115 | is( $red->rgb_hex, '#ff0000', 'named arg red has correct hex value'); | |
116 | is(($red->rgb)[0], 255, 'named arg red has correct rgb red component value'); | |
117 | is(($red->rgb)[1], 0, 'named arg red has correct rgb green component value'); | |
118 | is(($red->rgb)[2], 0, 'named arg red has correct rgb blue component value'); | |
119 | is(($red->hsl)[0], 0, 'named arg red has correct hsl hue component value'); | |
120 | is(($red->hsl)[1], 100, 'named arg red has correct hsl saturation component value'); | |
121 | is(($red->hsl)[2], 50, 'named arg red has correct hsl lightness component value'); | |
122 | ||
123 | $red = Chart::Color->new({Red => 255, Green => 0, Blue => 0 }); | |
124 | is( ref $red, $module, 'could create object by RGB hash ref'); | |
125 | is( $red->red, 255, 'hash ref red has correct red component value'); | |
126 | is( $red->green, 0, 'hash ref red has correct green component value'); | |
127 | is( $red->blue, 0, 'hash ref red has correct blue component value'); | |
128 | is( $red->hue, 0, 'hash ref red has correct hue component value'); | |
129 | is( $red->saturation, 100, 'hash ref red has correct saturation component value'); | |
130 | is( $red->lightness, 50, 'hash ref red has correct lightness component value'); | |
131 | is( $red->name, 'red', 'hash ref red has correct name'); | |
132 | is( $red->rgb_hex, '#ff0000', 'hash ref red has correct hex value'); | |
133 | is(($red->rgb)[0], 255, 'hash ref red has correct rgb red component value'); | |
134 | is(($red->rgb)[1], 0, 'hash ref red has correct rgb green component value'); | |
135 | is(($red->rgb)[2], 0, 'hash ref red has correct rgb blue component value'); | |
136 | is(($red->hsl)[0], 0, 'hash ref red has correct hsl hue component value'); | |
137 | is(($red->hsl)[1], 100, 'hash ref red has correct hsl saturation component value'); | |
138 | is(($red->hsl)[2], 50, 'hash ref red has correct hsl lightness component value'); | |
139 | ||
140 | $red = Chart::Color->new({h => 0, s => 100, l => 50 }); | |
141 | is( ref $red, $module, 'could create object by HSL hash ref'); | |
142 | is( $red->red, 255, 'hash ref red has correct red component value'); | |
143 | is( $red->green, 0, 'hash ref red has correct green component value'); | |
144 | is( $red->blue, 0, 'hash ref red has correct blue component value'); | |
145 | is( $red->hue, 0, 'hash ref red has correct hue component value'); | |
146 | is( $red->saturation, 100, 'hash ref red has correct saturation component value'); | |
147 | is( $red->lightness, 50, 'hash ref red has correct lightness component value'); | |
148 | is( $red->name, 'red', 'hash ref red has correct name'); | |
149 | is( $red->rgb_hex, '#ff0000', 'hash ref red has correct hex value'); | |
150 | is(($red->rgb)[0], 255, 'hash ref red has correct rgb red component value'); | |
151 | is(($red->rgb)[1], 0, 'hash ref red has correct rgb green component value'); | |
152 | is(($red->rgb)[2], 0, 'hash ref red has correct rgb blue component value'); | |
153 | is(($red->hsl)[0], 0, 'hash ref red has correct hsl hue component value'); | |
154 | is(($red->hsl)[1], 100, 'hash ref red has correct hsl saturation component value'); | |
155 | is(($red->hsl)[2], 50, 'hash ref red has correct hsl lightness component value'); | |
156 | ||
157 | $red = Chart::Color->new( Hue => 0, Sat => 100, Light => 50 ); | |
158 | is( ref $red, $module, 'could create object by HSL named args'); | |
159 | is( $red->red, 255, 'hash ref red has correct red component value'); | |
160 | is( $red->green, 0, 'hash ref red has correct green component value'); | |
161 | is( $red->blue, 0, 'hash ref red has correct blue component value'); | |
162 | is( $red->hue, 0, 'hash ref red has correct hue component value'); | |
163 | is( $red->saturation, 100, 'hash ref red has correct saturation component value'); | |
164 | is( $red->lightness, 50, 'hash ref red has correct lightness component value'); | |
165 | is( $red->name, 'red', 'hash ref red has correct name'); | |
166 | is( $red->rgb_hex, '#ff0000', 'hash ref red has correct hex value'); | |
167 | is(($red->rgb)[0], 255, 'hash ref red has correct rgb red component value'); | |
168 | is(($red->rgb)[1], 0, 'hash ref red has correct rgb green component value'); | |
169 | is(($red->rgb)[2], 0, 'hash ref red has correct rgb blue component value'); | |
170 | is(($red->hsl)[0], 0, 'hash ref red has correct hsl hue component value'); | |
171 | is(($red->hsl)[1], 100, 'hash ref red has correct hsl saturation component value'); | |
172 | is(($red->hsl)[2], 50, 'hash ref red has correct hsl lightness component value'); | |
173 | ||
174 | ||
175 | my $c = Chart::Color->new( 1,2,3 ); | |
176 | is( ref $red, $module, 'could create object by random unnamed color'); | |
177 | is( $c->red, 1, 'random color has correct red component value'); | |
178 | is( $c->green, 2, 'random color has correct green component value'); | |
179 | is( $c->blue, 3, 'random color has correct blue component value'); | |
180 | is( $c->name, '', 'random color has no name'); | |
181 | ||
182 | my $blue = Chart::Color->new( 'blue' ); | |
183 | is( $blue->red, 0, 'blue has correct red component value'); | |
184 | is( $blue->green, 0, 'blue has correct green component value'); | |
185 | is( $blue->blue, 255, 'blue has correct blue component value'); | |
186 | is( $blue->hue, 240, 'blue has correct hue component value'); | |
187 | is( $blue->saturation,100,'blue has correct saturation component value'); | |
188 | is( $blue->lightness, 50,'blue has correct lightness component value'); | |
189 | is( $blue->name, 'blue', 'blue color has correct name'); | |
190 | ||
191 | is( $blue->distance_to($red), 120, 'correct default hsl distance between red and blue'); | |
192 | is( $blue->distance_to($red, 'HSL'), 120, 'correct hsl distance between red and blue'); | |
193 | is( $blue->distance_to($red, 'Hue'), 120, 'correct hue distance between red and blue, long name'); | |
194 | is( $blue->distance_to($red, 'h'), 120, 'correct hue distance between red and blue'); | |
195 | is( $blue->distance_to($red, 's'), 0, 'correct sturation distance between red and blue'); | |
196 | is( $blue->distance_to($red, 'Sat'), 0, 'correct sturation distance between red and blue, long name'); | |
197 | is( $blue->distance_to($red, 'l'), 0, 'correct lightness distance between red and blue'); | |
198 | is( $blue->distance_to($red, 'Light'), 0, 'correct lightness distance between red and blue, long name'); | |
199 | is( $blue->distance_to($red, 'hs'), 120, 'correct hs distance between red and blue'); | |
200 | is( $blue->distance_to($red, 'hl'), 120, 'correct hl distance between red and blue'); | |
201 | is( $blue->distance_to($red, 'sl'), 0, 'correct sl distance between red and blue'); | |
202 | is( int $blue->distance_to($red, 'rgb'), 360, 'correct rgb distance between red and blue'); | |
203 | is( $blue->distance_to($red, 'Red'), 255, 'correct red distance between red and blue, long name'); | |
204 | is( $blue->distance_to($red, 'r'), 255, 'correct red distance between red and blue'); | |
205 | is( $blue->distance_to($red, 'Green'), 0, 'correct green distance between red and blue, long name'); | |
206 | is( $blue->distance_to($red, 'g'), 0, 'correct green distance between red and blue'); | |
207 | is( $blue->distance_to($red, 'Blue'), 255, 'correct blue distance between red and blue, long name'); | |
208 | is( $blue->distance_to($red, 'b'), 255, 'correct blue distance between red and blue'); | |
209 | is( $blue->distance_to($red, 'rg'), 255, 'correct rg distance between red and blue'); | |
210 | is( int $blue->distance_to($red, 'rb'), 360, 'correct rb distance between red and blue'); | |
211 | is( $blue->distance_to($red, 'gb'), 255, 'correct gb distance between red and blue'); | |
212 | ||
213 | is( int $blue->distance_to([10, 10, 245], ), 8, 'correct default hsl distance between own rgb blue and blue'); | |
214 | is( int $blue->distance_to([10, 10, 245], 'HSL'), 8, 'correct hsl distance between own rgb blue and blue'); | |
215 | is( $blue->distance_to([10, 10, 245], 'Hue'), 0, 'correct hue distance between own rgb blue and blue, long name'); | |
216 | is( $blue->distance_to([10, 10, 245], 'h'), 0, 'correct hue distance between own rgb blue and blue'); | |
217 | is( int $blue->distance_to([10, 10, 245], 's'), 8, 'correct sturation distance between own rgb blue and blue'); | |
218 | is( int $blue->distance_to([10, 10, 245], 'Sat'), 8, 'correct sturation distance between own rgb blue and blue, long name'); | |
219 | is( int $blue->distance_to([10, 10, 245], 'l'), 0, 'correct lightness distance between own rgb blue and blue'); | |
220 | is( int $blue->distance_to([10, 10, 245], 'Light'), 0, 'correct lightness distance between own rgb blue and blue, long name'); | |
221 | is( int $blue->distance_to([10, 10, 245], 'hs'), 8, 'correct hs distance between own rgb blue and blue'); | |
222 | is( int $blue->distance_to([10, 10, 245], 'hl'), 0, 'correct hl distance between own rgb blue and blue'); | |
223 | is( int $blue->distance_to([10, 10, 245], 'sl'), 8, 'correct sl distance between own rgb blue and blue'); | |
224 | is( int $blue->distance_to([10, 10, 245], 'rgb'), 17, 'correct rgb distance between own rgb blue and blue'); | |
225 | is( $blue->distance_to([10, 10, 245], 'Red'), 10, 'correct red distance between own rgb blue and blue, long name'); | |
226 | is( $blue->distance_to([10, 10, 245], 'r'), 10, 'correct red distance between own rgb blue and blue'); | |
227 | is( $blue->distance_to([10, 10, 245], 'Green'),10, 'correct green distance between own rgb blue and blue, long name'); | |
228 | is( $blue->distance_to([10, 10, 245], 'g'), 10, 'correct green distance between own rgb blue and blue'); | |
229 | is( $blue->distance_to([10, 10, 245], 'Blue'), 10, 'correct blue distance between own rgb blue and blue, long name'); | |
230 | is( $blue->distance_to([10, 10, 245], 'b'), 10, 'correct blue distance between own rgb blue and blue'); | |
231 | is( int $blue->distance_to([10, 10, 245], 'rg'), 14, 'correct rg distance between own rgb blue and blue'); | |
232 | is( int $blue->distance_to([10, 10, 245], 'rb'), 14, 'correct rb distance between own rgb blue and blue'); | |
233 | is( int $blue->distance_to([10, 10, 245], 'gb'), 14, 'correct gb distance between own rgb blue and blue'); | |
234 | ||
235 | is( int $blue->distance_to({h =>230, s => 90, l=>40}), 17, 'correct default hsl distance between own hsl blue and blue'); | |
236 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'HSL'), 17, 'correct hsl distance between own hsl blue and blue'); | |
237 | is( $blue->distance_to({h =>230, s => 90, l=>40}, 'Hue'), 10, 'correct hue distance between own hsl blue and blue, long name'); | |
238 | is( $blue->distance_to({h =>230, s => 90, l=>40}, 'h'), 10, 'correct hue distance between own hsl blue and blue'); | |
239 | is( $blue->distance_to({h =>230, s => 90, l=>40}, 's'), 10, 'correct sturation distance between own hsl blue and blue'); | |
240 | is( $blue->distance_to({h =>230, s => 90, l=>40}, 'Sat'), 10, 'correct sturation distance between own hsl blue and blue, long name'); | |
241 | is( $blue->distance_to({h =>230, s => 90, l=>40}, 'l'), 10, 'correct lightness distance between own hsl blue and blue'); | |
242 | is( $blue->distance_to({h =>230, s => 90, l=>40}, 'Light'),10, 'correct lightness distance between own hsl blue and blue, long name'); | |
243 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'hs'), 14, 'correct hs distance between own hsl blue and blue'); | |
244 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'hl'), 14, 'correct hl distance between own hsl blue and blue'); | |
245 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'sl'), 14, 'correct sl distance between own hsl blue and blue'); | |
246 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'rgb'), 74, 'correct rgb distance between own hsl blue and blue'); | |
247 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'Red'), 10, 'correct red distance between own hsl blue and blue, long name'); | |
248 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'r'), 10, 'correct red distance between own hsl blue and blue'); | |
249 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'Green'),41, 'correct green distance between own hsl blue and blue, long name'); | |
250 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'g'), 41, 'correct green distance between own hsl blue and blue'); | |
251 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'Blue'), 61, 'correct blue distance between own hsl blue and blue, long name'); | |
252 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'b'), 61, 'correct blue distance between own hsl blue and blue'); | |
253 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'rg'), 42, 'correct rg distance between own hsl blue and blue'); | |
254 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'rb'), 61, 'correct rb distance between own hsl blue and blue'); | |
255 | is( int $blue->distance_to({h =>230, s => 90, l=>40}, 'gb'), 73, 'correct gb distance between own hsl blue and blue'); | |
256 | ||
257 | $red = Chart::Color->new('#FF0000'); | |
258 | warning_like {$red->add()} {carped => qr/argument options/}, "need argument to add to color object"; | |
259 | warning_like {$red->add('weirdcolorname')} {carped => qr/unknown color/}, "accept only known color names"; | |
260 | warning_like {$red->add('#23232') } {carped => qr/hex color definition/}, "hex definition too short"; | |
261 | warning_like {$red->add('#232321f') } {carped => qr/hex color definition/}, "hex definition too long"; | |
262 | warning_like {$red->add(1,1)} {carped => qr/argument options/}, "too few positional args"; | |
263 | warning_like {$red->add(1,1,1,1)} {carped => qr/wrong number/}, "too many positional args"; | |
264 | warning_like {$red->add([1,1])} {carped => qr/ 3 numerical values/}, "too few positional args in ref"; | |
265 | warning_like {$red->add([1,1,1,1])} {carped => qr/ 3 numerical values/}, "too many positional args in ref"; | |
266 | warning_like {$red->add(r=>1,g=>1,t=>1)} {carped => qr/unknown hash key/}, "don't invent named args"; | |
267 | warning_like {$red->add({r=>1,g=>1,t=>1})} {carped => qr/unknown hash key/}, "don't invent named args, in ref"; | |
268 | ||
269 | my $white = Chart::Color->new('white'); | |
270 | my $black = Chart::Color->new('black'); | |
271 | ||
272 | is( $white->add( 255, 255, 255 )->name, 'white', "it can't get whiter than white with additive color adding"); | |
273 | is( $white->add( {Hue => 10} )->name, 'white', "hue doesnt change when were on level white"); | |
274 | is( $white->add( {Red => 10} )->name, 'white', "hue doesnt change when adding red on white"); | |
275 | is( $white->add( $white )->name, 'white', "adding white on white is still white"); | |
276 | is( $red->add( $black )->name, 'red', "red + black = red"); | |
277 | is( $red->add( $black, -1 )->name, 'red', "red - black = red"); | |
278 | is( $white->add( $red, -1 )->name, 'aqua', "white - red = aqua"); | |
279 | is( $white->add( $white, -0.5 )->name, 'gray', "white - 0.5 white = grey"); | |
280 | is( Chart::Color->new(1,2,3)->add( 2,1,0)->name, 'gray1', "adding positional args"); # = 3, 3, 3 | |
281 | is( $red->add( {Saturation => -10} )->red, 242, "paling red 10%, red value"); | |
282 | is( $red->add( {Saturation => -10} )->blue, 13, "paling red 10%, blue value"); | |
283 | is( $white->add( {Lightness => -12} )->name, 'gray88', "dimming white 12%"); | |
284 | is( $black->add( {Red => 255} )->name, 'red', "creating pure red from black"); | |
285 | is( $black->add( {Green => 255} )->name, 'lime', "creating pure green from black"); | |
286 | is( $black->add( { b => 255} )->name, 'blue', "creating pure blue from black with short name"); | |
287 | ||
288 | ||
289 | warning_like {$red->blend_with()} {carped => qr/color object/}, "need argument to blend to color object"; | |
290 | warning_like {$red->blend_with('weirdcolorname')} {carped => qr/unknown color/}, "accept only known color names"; | |
291 | warning_like {$red->blend_with('#23232') } {carped => qr/hex color definition/}, "hex definition too short"; | |
292 | warning_like {$red->blend_with('#232321f') } {carped => qr/hex color definition/}, "hex definition too long"; | |
293 | warning_like {$red->blend_with([1,1])} {carped => qr/need exactly 3/}, "too few positional args in ref"; | |
294 | warning_like {$red->blend_with([1,1,1,1])} {carped => qr/need exactly 3/}, "too many positional args in ref"; | |
295 | warning_like {$red->blend_with({r=>1,g=>1,t=>1})} {carped => qr/argument keys/}, "don't mix named args, in hash ref color def"; | |
296 | warning_like {$red->blend_with({r=>1,g=>1,l=>1})} {carped => qr/argument keys/}, "don't invent named args, in hash ref color def"; | |
297 | ||
298 | is( $black->blend_with( $white )->name, 'gray', "blend black + white = gray"); | |
299 | is( $black->blend_with( $white, 0 )->name, 'black', "blend nothing, keep color"); | |
300 | is( $black->blend_with( $white, 1 )->name, 'white', "blend nothing, take c2"); | |
301 | is( $black->blend_with( $white, 2 )->name, 'white', "RGB limits kept"); | |
302 | is( $red->blend_with( 'blue')->name, 'fuchsia', "blending with name"); | |
303 | is( $red->blend_with( '#0000ff')->name, 'fuchsia', "blending with hex def"); | |
304 | is( $red->blend_with( [0,0,255])->name, 'fuchsia', "blending with array ref color def"); | |
305 | is( $red->blend_with({R=> 0, G=> 0, B=>255})->name, 'fuchsia', "blending with RGB hash ref color def"); | |
306 | is( $red->blend_with({H=> 240, S=> 100, L=>50})->name,'fuchsia', "blending with HSL hash ref color def"); | |
307 | ||
308 | is( $black->gradient_to( $white, 1 )->name, 'black', 'shortest gradient is $self'); | |
309 | my @g = $black->gradient_to( $white, 2 ); | |
310 | is( int @g, 2, 'gradient with length 2 has only boundary cases'); | |
311 | is( $g[0]->name, 'black', 'gradient with length 2 starts on left boundary'); | |
312 | is( $g[1]->name, 'white', 'gradient with length 2 ends on right boundary'); | |
313 | @g = $black->gradient_to( $white, 6 ); | |
314 | is( int @g, 6, 'gradient has right length = 6'); | |
315 | is( $g[1]->name, 'gray20', 'grey20 is between black and white'); | |
316 | is( $g[2]->name, 'gray40', 'grey40 is between black and white'); | |
317 | @g = $black->gradient_to( $white, 3, 2 ); | |
318 | is( int @g, 3, 'gradient has right length = 3'); | |
319 | is( $g[1]->name, 'gray25', 'grey25 is between black and white in none linear gradient'); | |
320 | @g = $black->gradient_to( $white, 3, .41 ); | |
321 | is( $g[1]->name, 'gray75', 'grey75 is between black and white in none linear gradient'); | |
322 | @g = $red->gradient_to( '#0000FF', 3 ); | |
323 | is( $g[1]->name, 'fuchsia', 'fuchsia is between red and blue in linear gradient'); | |
324 | ||
325 | @g = $black->complementary(); | |
326 | is( int @g, 1, "default is one complementary color"); | |
327 | is( $black->complementary()->name, 'black', "black has no complementary color"); | |
328 | is( $white->complementary()->name, 'white', "white has no complementary color"); | |
329 | is( $red->complementary()->name, 'aqua', "aqua is complementary to red"); | |
330 | ||
331 | @g = $red->complementary(3); | |
332 | is( int @g, 3, "requested amount of complementary colors"); | |
333 | is( $g[0]->saturation, $g[1]->saturation, "saturation is equal on complementary circle"); | |
334 | is( $g[1]->saturation, $g[2]->saturation, "saturation is equal on complementary circle 2"); | |
335 | is( $g[0]->lightness, $g[1]->lightness, "lightness is equal on complementary circle"); | |
336 | is( $g[1]->lightness, $g[2]->lightness, "lightness is equal on complementary circle 2"); | |
337 | is( $g[0]->name, 'red', "complementary circle starts with C1"); | |
338 | is( $g[1]->name, 'lime', "complementary gos on to green"); | |
339 | is( $g[2]->name, 'blue', "complementary circle ends with blue"); | |
340 | ||
341 | @g = Chart::Color->new(15,12,13)->complementary(3); | |
342 | is( $g[0]->saturation, $g[1]->saturation, "saturation is equal on complementary circle of random color"); | |
343 | is( $g[1]->saturation, $g[2]->saturation, "saturation is equal on complementary circle 2"); | |
344 | is( $g[0]->lightness, $g[1]->lightness, "lightness is equal on complementary circle of random color"); | |
345 | is( $g[1]->lightness, $g[2]->lightness, "lightness is equal on complementary circle 2"); | |
346 | ||
347 | @g = Chart::Color->new(15,12,13)->complementary(4, 12, 20); | |
348 | is( int @g, 4, "requested amount of complementary colors"); | |
349 | is( $g[1]->saturation, $g[3]->saturation, "saturation is equal on opposing sides of skewed circle"); | |
350 | is( $g[1]->lightness, $g[3]->lightness, "lightness is equal on opposing sides of skewed circle"); | |
351 | is( $g[1]->saturation-6, $g[0]->saturation, "saturation moves on skewed circle as predicted fore "); | |
352 | is( $g[1]->saturation+6, $g[2]->saturation, "saturation moves on skewed circle as predicted back"); | |
353 | is( $g[1]->lightness-10, $g[0]->lightness, "lightness moves on skewed circle as predicted fore"); | |
354 | is( $g[1]->lightness+10, $g[2]->lightness, "lightness moves on skewed circle as predicted back"); | |
355 | ||
356 | @g = Chart::Color->new(15,12,13)->complementary(4, 512, 520); | |
357 | is( abs($g[0]->saturation-$g[2]->saturation) < 100, 1, "cut too large saturnation skews"); | |
358 | is( abs($g[0]->lightness-$g[2]->lightness) < 100, 1, "cut too large lightness skews"); | |
359 | ||
360 | @g = Chart::Color->new(15,12,13)->complementary(5, 10, 20); | |
361 | is( $g[1]->saturation, $g[4]->saturation, "saturation is equal on opposing sides of odd and skewed circle 1"); | |
362 | is( $g[2]->saturation, $g[3]->saturation, "saturation is equal on opposing sides of odd and skewed circle 2"); | |
363 | is( $g[1]->lightness, $g[4]->lightness, "lightness is equal on opposing sides of odd and skewed circle 1"); | |
364 | is( $g[2]->lightness, $g[3]->lightness, "lightness is equal on opposing sides of odd and skewed circle 2"); | |
365 | is( $g[1]->saturation-4, $g[0]->saturation, "saturation moves on odd and skewed circle as predicted fore "); | |
366 | is( $g[1]->saturation+4, $g[2]->saturation, "saturation moves on odd and skewed circle as predicted back"); | |
367 | is( $g[1]->lightness -8, $g[0]->lightness, "lightness moves on odd and skewed circle as predicted fore"); | |
368 | is( $g[1]->lightness +8, $g[2]->lightness, "lightness moves on odd and skewed circle as predicted back"); | |
369 | ||
370 | ||
371 | exit 0; |