File Coverage

blib/lib/Term/Colormap.pm
Criterion Covered Total %
statement 80 82 97.5
branch 16 16 100.0
condition 7 7 100.0
subroutine 19 20 95.0
pod 11 11 100.0
total 133 136 97.7


line stmt bran cond sub pod time code
1             package Term::Colormap;
2              
3 2     2   124827 use 5.006;
  2         12  
4 2     2   9 use strict;
  2         3  
  2         34  
5 2     2   34 use warnings FATAL => 'all';
  2         3  
  2         69  
6 2     2   10 use Exporter 'import';
  2         2  
  2         72  
7 2     2   10 use Scalar::Util qw( looks_like_number );
  2         3  
  2         2402  
8              
9             our $VERSION = '0.19';
10              
11             our @EXPORT_OK = qw(
12             add_mapping
13             color2rgb
14             color_table
15             colorbar
16             colored
17             colored_text
18             colormap
19             colormap_names
20             print_colored
21             print_colored_text
22             rgb2color
23             );
24              
25             my $color_mapping = {};
26              
27             # http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html
28             $color_mapping->{rainbow} = [
29             1, # Red
30             196, 202, 208, 214, 220, 226,
31             11, # Yellow
32             190, 154, 118, 82, 46,
33             10, # Green
34             47, 48, 49, 50, 51,
35             14, # Cyan
36             45, 39, 33, 27, 21,
37             12, # Blue
38             57, 93, 129, 165, 201,
39             5, # Magenta
40             ];
41              
42             $color_mapping->{primary} = [
43             # Black, Red, Green, Yellow, Blue, Magenta, Cyan, Off-White
44             0,1,2,3,4,5,6,7
45             ];
46              
47             $color_mapping->{bright} = [
48             # Gray, Bright Red, Bright Green, Bright Yellow,
49             8,9,10,11,
50             # Bright Blue, Bright Magenta, Bright Cyan, White
51             12,13,14,15
52             ];
53              
54             $color_mapping->{ash} = [
55             # Black <--------------------------------> Gray
56             232,233,234,235,236,237,238,239,240,241,242,243,
57             ];
58              
59             $color_mapping->{snow} = [
60             # Gray <--------------------------------> White
61             244,245,246,247,248,249,250,251,252,253,254,255,
62             ];
63              
64             $color_mapping->{gray} = [ @{ $color_mapping->{ash} }, @{ $color_mapping->{snow} } ];
65              
66             $color_mapping->{'blue-cyan-green'} = [
67             # Blue <------------------ Cyan -----------------> Green
68             17,18,19,20,21,27,33,39,45,51,50,49,48,47,46,40,34,28,22
69             ];
70              
71             $color_mapping->{'red-pink-yellow'} = [
72             # Red <------------------ Pink ------------------------> Yellow
73             196,197,198,199,200,201,207,213,219,225,231,230,229,228,227,226
74             ];
75              
76             $color_mapping->{'green-orange-pink-blue'} = [
77             # Green <-------- Orange -------- Pink --------------> Blue
78             28,64,100,136,172,208,209,210,211,212,213,177,141,105,69,33
79             ];
80              
81             # 0-255
82             my $color2rgb = [
83             '000000', '800000', '008000', '808000', '000080', '800080',
84             '008080', 'c0c0c0', '808080', 'ff0000', '00ff00', 'ffff00',
85             '0000ff', 'ff00ff', '00ffff', 'ffffff', '000000', '00005f',
86             '000087', '0000af', '0000d7', '0000ff', '005f00', '005f5f',
87             '005f87', '005faf', '005fd7', '005fff', '008700', '00875f',
88             '008787', '0087af', '0087d7', '0087ff', '00af00', '00af5f',
89             '00af87', '00afaf', '00afd7', '00afff', '00d700', '00d75f',
90             '00d787', '00d7af', '00d7d7', '00d7ff', '00ff00', '00ff5f',
91             '00ff87', '00ffaf', '00ffd7', '00ffff', '5f0000', '5f005f',
92             '5f0087', '5f00af', '5f00d7', '5f00ff', '5f5f00', '5f5f5f',
93             '5f5f87', '5f5faf', '5f5fd7', '5f5fff', '5f8700', '5f875f',
94             '5f8787', '5f87af', '5f87d7', '5f87ff', '5faf00', '5faf5f',
95             '5faf87', '5fafaf', '5fafd7', '5fafff', '5fd700', '5fd75f',
96             '5fd787', '5fd7af', '5fd7d7', '5fd7ff', '5fff00', '5fff5f',
97             '5fff87', '5fffaf', '5fffd7', '5fffff', '870000', '87005f',
98             '870087', '8700af', '8700d7', '8700ff', '875f00', '875f5f',
99             '875f87', '875faf', '875fd7', '875fff', '878700', '87875f',
100             '878787', '8787af', '8787d7', '8787ff', '87af00', '87af5f',
101             '87af87', '87afaf', '87afd7', '87afff', '87d700', '87d75f',
102             '87d787', '87d7af', '87d7d7', '87d7ff', '87ff00', '87ff5f',
103             '87ff87', '87ffaf', '87ffd7', '87ffff', 'af0000', 'af005f',
104             'af0087', 'af00af', 'af00d7', 'af00ff', 'af5f00', 'af5f5f',
105             'af5f87', 'af5faf', 'af5fd7', 'af5fff', 'af8700', 'af875f',
106             'af8787', 'af87af', 'af87d7', 'af87ff', 'afaf00', 'afaf5f',
107             'afaf87', 'afafaf', 'afafd7', 'afafff', 'afd700', 'afd75f',
108             'afd787', 'afd7af', 'afd7d7', 'afd7ff', 'afff00', 'afff5f',
109             'afff87', 'afffaf', 'afffd7', 'afffff', 'd70000', 'd7005f',
110             'd70087', 'd700af', 'd700d7', 'd700ff', 'd75f00', 'd75f5f',
111             'd75f87', 'd75faf', 'd75fd7', 'd75fff', 'd78700', 'd7875f',
112             'd78787', 'd787af', 'd787d7', 'd787ff', 'd7af00', 'd7af5f',
113             'd7af87', 'd7afaf', 'd7afd7', 'd7afff', 'd7d700', 'd7d75f',
114             'd7d787', 'd7d7af', 'd7d7d7', 'd7d7ff', 'd7ff00', 'd7ff5f',
115             'd7ff87', 'd7ffaf', 'd7ffd7', 'd7ffff', 'ff0000', 'ff005f',
116             'ff0087', 'ff00af', 'ff00d7', 'ff00ff', 'ff5f00', 'ff5f5f',
117             'ff5f87', 'ff5faf', 'ff5fd7', 'ff5fff', 'ff8700', 'ff875f',
118             'ff8787', 'ff87af', 'ff87d7', 'ff87ff', 'ffaf00', 'ffaf5f',
119             'ffaf87', 'ffafaf', 'ffafd7', 'ffafff', 'ffd700', 'ffd75f',
120             'ffd787', 'ffd7af', 'ffd7d7', 'ffd7ff', 'ffff00', 'ffff5f',
121             'ffff87', 'ffffaf', 'ffffd7', 'ffffff', '080808', '121212',
122             '1c1c1c', '262626', '303030', '3a3a3a', '444444', '4e4e4e',
123             '585858', '626262', '626262', '767676', '808080', '8a8a8a',
124             '949494', '9e9e9e', 'a8a8a8', 'b2b2b2', 'bcbcbc', 'c6c6c6',
125             'd0d0d0', 'dadada', 'e4e4e4', 'eeeeee',
126             ];
127              
128             my $color = 0;
129             my $rgb2color = { map { $_ => $color++ } @$color2rgb };
130              
131             sub add_mapping {
132 0     0 1 0 my ($name, $mapping) = @_;
133 0         0 $color_mapping->{$name} = $mapping;
134             }
135              
136             sub rgb2color {
137 1247     1247 1 66925 my ($rgb) = @_;
138              
139 1247         1469 my $original_rgb = $rgb;
140 1247         1835 $rgb =~ s|^#||;
141 1247         1739 $rgb = lc($rgb);
142 1247 100       2804 if ( $rgb =~ m|[^a-f0-9]| ) {
143 1         10 die "Invalid RGB color '$original_rgb'"
144             }
145              
146 1246 100       2476 unless (defined $rgb2color->{$rgb}) {
147 1000         1474 $rgb2color->{ $rgb } = $rgb2color->{ _get_nearest_color($rgb) };
148             }
149              
150 1246         2603 return $rgb2color->{$rgb};
151             }
152              
153             sub _get_nearest_color {
154 1000     1000   1281 my ($rgb) = @_;
155 1000         1279 my $closest = 3 * (scalar @$color2rgb);
156 1000         1009 my $best_color;
157 1000         1458 for my $color ( @$color2rgb ) {
158 256000         307120 my $dist = _color_distance($rgb, $color);
159 256000 100       422168 if ($dist < $closest) {
160 5132         5275 $best_color = $color;
161 5132         6173 $closest = $dist;
162             }
163             }
164 1000         3509 return $best_color;
165             }
166              
167             sub _color_distance {
168 256000     256000   311474 my ($rgb0, $rgb1) = @_;
169 256000         311457 my $rgb = $rgb0 . $rgb1;
170             my ($r0, $g0, $b0,
171 256000         779441 $r1, $g1, $b1) = map { hex } ( $rgb =~ m/../g );
  1536000         1751643  
172 256000         480736 return abs($r1 - $r0)
173             + abs($g1 - $g0)
174             + abs($b1 - $b0);
175             }
176              
177             sub colormap {
178 14     14 1 2678 my ($name) = @_;
179              
180 14 100       50 if ( exists $color_mapping->{ lc($name) } ) {
181 13         35 return $color_mapping->{ lc($name) };
182             }
183              
184 1         14 die "Invalid colormap name : '$name'\n" .
185             "Choose one of ( " . ( join ", ", sort keys %$color_mapping ) . " )\n";
186              
187             }
188              
189             sub colormap_names {
190              
191 1     1 1 236 return sort keys %$color_mapping;
192              
193             }
194              
195             sub color2rgb {
196 321     321 1 60702 my ($color) = @_;
197              
198 321 100 100     1067 if ($color < 0 or $color >= scalar @$color2rgb) {
199 4         32 die "Invalid color value : $color";
200             }
201              
202 316         1053 return $color2rgb->[$color];
203             }
204              
205              
206             sub colorbar {
207 2     2 1 3849 my ($colors, $width, $orientation ) = @_;
208              
209 2   100     10 $width ||= 2;
210 2   100     9 $orientation ||= 'h'; # Horizontal
211              
212 2         4 for my $color (@$colors) {
213 64         185 print_colored( $color, ' 'x$width );
214 64 100       242 unless ('h' eq substr(lc($orientation),0,1)) {
215 32         262 print "\n";
216             }
217             }
218 2         23 print "\n";
219             }
220              
221             sub color_table {
222 3     3 1 8268 my ($name) = @_;
223 3         10 my $mapping = colormap($name);
224              
225 3         7 my $header = "color number rgb";
226 3         10 my $indent = (length($header) - length($name) - 1) / 2; # spaces around name
227              
228 3         6 my $ii = int($indent);
229 3         88 print '-'x$ii . " $name " . '-'x$ii;
230 3 100       24 print '-' if ($ii < $indent);
231 3         29 print "\n";
232              
233 3         28 print $header . "\n";
234 3         8 for my $color (@$mapping) {
235 60         193 print_colored($color, ' 'x8 );
236 60         234 print sprintf(" %3d ", $color) . color2rgb($color) . "\n";
237             }
238 3         43 print "\n";
239             }
240              
241             sub print_colored {
242 125     125 1 2042 my ($color, $txt) = @_;
243 125         156 _print_with_color('bg',$color,$txt);
244             }
245              
246             sub print_colored_text {
247 1     1 1 1549 my ($color, $txt) = @_;
248 1         3 _print_with_color('fg',$color,$txt);
249             }
250              
251             sub _print_with_color {
252 126     126   172 my ($bg_or_fg, $color, $txt) = @_;
253 126         173 print _get_colored_string($bg_or_fg, $color, $txt);
254             }
255              
256             sub colored {
257 1     1 1 233 my ($color, $txt) = @_;
258 1         3 return _get_colored_string('bg', $color, $txt)
259             }
260              
261             sub colored_text {
262 1     1 1 898 my ($color, $txt) = @_;
263 1         3 return _get_colored_string('fg', $color, $txt)
264             }
265              
266             sub _get_colored_string {
267 128     128   155 my ($bg_or_fg, $color, $txt) = @_;
268              
269 128 100       203 my $code = $bg_or_fg eq 'fg' ? 38 : 48;
270 128         1278 return "\x1b[${code};5;${color}m" . $txt . "\x1b[0m";
271             }
272              
273             1; # End of Term::Colormap
274              
275             __END__