[Bio] / FigKernelPackages / gjocolorlib.pm Repository:
ViewVC logotype

Annotation of /FigKernelPackages/gjocolorlib.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (view) (download) (as text)

1 : overbeek 1.1 package gjocolorlib;
2 :    
3 : golsen 1.7 #===============================================================================
4 :     # Utilities for manipulating colors.
5 :     #
6 :     # Based on component values from 0 to 1; undefined values are silently set
7 :     # to 0. Unless stated otherwise, RGB values are linear, and HTML color
8 :     # values are sRGB.
9 : overbeek 1.1 #
10 : golsen 1.7 # @rgb = ( $red, $green, $blue ) # gamma 1.0
11 :     # @srgb = ( $red, $green, $blue ) # WWW std for pseudo gamma 2.2
12 :     # @hsb = ( $hue, $saturation, $brightness ) # hue = 0 is red
13 :     # @hsy = ( $hue, $saturation, $luma ) # luma is percieved brightness
14 :     # @cmy = ( $cyan, $magenta, $yellow )
15 :     # @cmyk = ( $cyan, $magenta, $yellow, $black )
16 :     # $html = '#xxxxxx', or named color
17 : overbeek 1.1 #
18 : golsen 1.7 # With very few exepctions, all exported functions take color components,
19 :     # or a reference to an array of color components. Similarly, output is
20 :     # an array of components, or a reference to an array of color components,
21 :     # depending on context.
22 : overbeek 1.1 #
23 :     # Exported functions:
24 :     #
25 : golsen 1.7 # @srgb = rgb2srgb( @rgb )
26 :     # @rgb = srgb2rgb( @srgb )
27 :     #
28 : overbeek 1.1 # @rgb = hsb2rgb( @hsb )
29 : golsen 1.7 # @rgb = hsy2rgb( @hsy )
30 :     # @hsb = rgb2hsb( @rgb )
31 :     # @hsy = rgb2hsy( @rgb )
32 :     #
33 : overbeek 1.1 # @rgb = cmy2rgb( @cmy )
34 :     # @rgb = cmyk2rgb( @cmyk )
35 : golsen 1.7 # @cmy = rgb2cym( @rgb )
36 :     # @cmyk = rgb2cymk( @rgb )
37 :     #
38 :     # $gray = rgb2gray( @rgb )
39 :     # @rgb = gray2rgb( $gray )
40 :     #
41 :     # @rgb = html2rgb( $html ) # name or hex sRGB to RGB
42 :     # $html = rgb2html( @rgb ) # linear RGB to sRGB html
43 :     # $html = rgb2html_g10( @rgb ) # gamma = 1.0, or @rgb is sRGB
44 :     # $html = rgb2html_g18( @rgb ) # gamma = 1.8
45 :     # $html = rgb2html_g22( @rgb ) # gamma = 2.2
46 :     # $html = gray2html( $gray ) # linear gray to sRGB html
47 :     # $html = gray2html_g10( $gray ) # gamma = 1.0
48 :     # $html = gray2html_g18( $gray ) # gamma = 1.8
49 :     # $html = gray2html_g22( $gray ) # gamma = 2.2
50 :     # $name = rgb2name( @rgb ) # CSS 3.0 and SVG 1.0 colors
51 :     #
52 :     # @rgb = blend_rgb_colors( \@color1, \@color2, ... )
53 :     # $html = blend_html_colors( $html1, $html2, ... )
54 : overbeek 1.1 #
55 : golsen 1.7 # Internal functions for validated input values (no reference as input):
56 :     #
57 :     # @srgb = linear2srgb( @rgb )
58 :     # @rgb = srgb2linear( @srgb )
59 :     # @rgb = hs2rgb( $hue, $saturation ) # brighness = 1
60 :     # @rgb = rgb2hsb0( @rgb )
61 :     # $gray = rgb2gray0( @rgb )
62 :     # \@rgb = htmlhex2rgb( $html ) # returns reference due to its usage
63 :     # $html = srgb2html0( @srgb )
64 :     # $dist = rgb_distance( \@rgb1, \@rgb2 )
65 :     #
66 :     # Internal data include:
67 :     #
68 :     # @name2rgb # Array of CamalCase standard color names and RGB values
69 :     # # used to match name to given RGB value
70 :     # %lc_name2rgb # Hash from lowercase name to RGB values (includes some
71 :     # # nonstandard names)
72 :     #
73 :     #===============================================================================
74 : overbeek 1.1
75 : golsen 1.7 use strict;
76 : overbeek 1.1
77 :     require Exporter;
78 :    
79 :     our @ISA = qw(Exporter);
80 :     our @EXPORT = qw(
81 : golsen 1.7 rgb2srgb
82 :     srgb2rgb
83 : overbeek 1.1 hsb2rgb
84 : golsen 1.7 hsy2rgb
85 : overbeek 1.1 cmy2rgb
86 :     cmyk2rgb
87 : golsen 1.7 rgb2gray
88 :     gray2rgb
89 : overbeek 1.1 html2rgb
90 :     rgb2html
91 : golsen 1.7 rgb2html_g10
92 :     rgb2html_g18
93 :     rgb2html_g22
94 : golsen 1.4 gray2html
95 : golsen 1.7 gray2html_g10
96 :     gray2html_g18
97 :     gray2html_g22
98 : overbeek 1.1 rgb2name
99 :     blend_rgb_colors
100 :     blend_html_colors
101 :     );
102 :     our @EXPORT_OK = qw(
103 :     UI_Orange
104 :     UI_Formal_Orange
105 :     UI_Blue
106 :     UI_Formal_Blue
107 :     );
108 :    
109 :    
110 : golsen 1.7 my $UI_Blue = [ 125/255, 60/255, 125/255 ];
111 :     my $UI_Orange = [ 244/255, 127/255, 36/255 ];
112 :     my $UI_Formal_Blue = [ 110/255, 139/255, 191/255 ];
113 :     my $UI_Formal_Orange = [ 239/255, 138/255, 28/255 ];
114 :    
115 :     # Use floor to get proper modulo 1 values
116 :    
117 :     sub floor
118 :     {
119 :     my $x = $_[0] || 0;
120 : overbeek 1.1 ( $x >= 0 ) || ( int($x) == $x ) ? int( $x ) : -1 - int( - $x )
121 :     }
122 :    
123 : golsen 1.7 sub min { ( $_[0] < $_[1] ) ? $_[0] : $_[1] }
124 :     sub max { ( $_[0] > $_[1] ) ? $_[0] : $_[1] }
125 :    
126 :     #
127 :     # Many values need to be clipped to a range from 0 to 1. The first function
128 :     # returns a value in the range. It creates the value if necessary. The
129 :     # second function adjusts args in place. It cannot create a value.
130 :     #
131 :     # $zero2one = zero2one( $val )
132 :     #
133 :    
134 :     sub zero2one { local $_ = $_[0]; ( ! defined || ( $_ <= 0 ) ) ? 0 : $_ > 1 ? 1 : $_ }
135 : overbeek 1.1
136 : golsen 1.7 #
137 :     # make_zero2one( $a, $b, ... )
138 :     #
139 :    
140 :     sub make_zero2one # in place
141 :     {
142 :     foreach ( @_ )
143 :     {
144 :     if ( ! defined || $_ <= 0 ) { $_ = 0 } elsif ( $_ > 1 ) { $_ = 1 }
145 :     }
146 : overbeek 1.1 }
147 :    
148 : golsen 1.7 #===============================================================================
149 :     # Conversions between linear RGB and sRGB, the standard for default color
150 :     # values.
151 :     #-------------------------------------------------------------------------------
152 :     # The breakpoints for the conversions are different in the specification at
153 :     # www.w3.org and the version on wikipedia.org. The latter actually matches
154 :     # values to more decimal places and is used here.
155 :     #
156 :     # http://www.w3.org/Graphics/Color/sRGB.html
157 :     # http://en.wikipedia.org/wiki/SRGB
158 :     #
159 :     #-------------------------------------------------------------------------------
160 :     # Internal functions for doing the forward and reverse transforms from
161 :     # validated triplets:
162 :     #
163 :     # @sRGB = linear2srgb( @RGB )
164 :     # @RGB = srgb2linear( @sRGB )
165 :     #
166 :     #-------------------------------------------------------------------------------
167 :     sub linear2srgb
168 :     {
169 :     # map { $_ <= 0.00314 ? 12.92*$_ : 1.055*($_**(1/2.4))-0.055 } @_ # w3.org spec
170 :     map { $_ <= 0.0031308 ? 12.92*$_ : 1.055*($_**(1/2.4))-0.055 } @_ # wiki spec
171 :     }
172 :    
173 :    
174 :     sub srgb2linear
175 :     {
176 :     # map { $_ <= 0.03928 ? $_/12.92 : (($_+0.055)/1.055)**2.4 } @_ # w3.org spec
177 :     map { $_ <= 0.04045 ? $_/12.92 : (($_+0.055)/1.055)**2.4 } @_ # wiki spec
178 :     }
179 :    
180 :    
181 :     #-------------------------------------------------------------------------------
182 :     # External functions for doing the forward and reverse transforms:
183 :     #
184 :     # \@sRGB = rgb2srgb( \@RGB )
185 :     # \@sRGB = rgb2srgb( @RGB )
186 :     # @sRGB = rgb2srgb( \@RGB )
187 :     # @sRGB = rgb2srgb( @RGB )
188 :     #
189 :     # \@RGB = srgb2rgb( \@sRGB )
190 :     # \@RGB = srgb2rgb( @sRGB )
191 :     # @RGB = srgb2rgb( \@sRGB )
192 :     # @RGB = srgb2rgb( @sRGB )
193 :     #
194 :     #-------------------------------------------------------------------------------
195 :     sub rgb2srgb
196 :     {
197 :     my ( $r, $g, $b ) = $_[0] && ref( $_[0] ) eq 'ARRAY' ? @{$_[0]} : @_;
198 :     make_zero2one( $r, $g, $b );
199 :     my @srgb = linear2srgb( $r, $g, $b );
200 :     wantarray ? @srgb : \@srgb;
201 :     }
202 : overbeek 1.1
203 : golsen 1.7
204 :     sub srgb2rgb
205 :     {
206 :     my ( $r, $g, $b ) = $_[0] && ref( $_[0] ) eq 'ARRAY' ? @{$_[0]} : @_;
207 :     make_zero2one( $r, $g, $b );
208 :     my @rgb = srgb2linear( $r, $g, $b );
209 :     wantarray ? @rgb : \@rgb;
210 : overbeek 1.1 }
211 :    
212 :    
213 : golsen 1.7 #-------------------------------------------------------------------------------
214 :     # Look-up table for 0 - 255 index of sRGB (i.e., html hex values) to
215 :     # linear RGB value in 0-1 range.
216 :     #-------------------------------------------------------------------------------
217 :    
218 :     my @index2rgb = map { srgb2linear( $_/255 ) } ( 0 .. 255 );
219 :    
220 :    
221 :     #===============================================================================
222 :     # Interconversions of RGB and HSB and HSY values. HSY is same idea as HSB,
223 :     # but with luma (the visual lightness, y, range 0 - 1). Colors are darkened
224 :     # or desaturated as necessary to match the luma value.
225 :     #
226 :     # @rgb = hsb2rgb( @hsb )
227 :     # @rgb = hsy2rgb( @hsy )
228 :     # @hsb = rgb2hsb( @rgb )
229 :     # @hsy = rgb2hsy( @rgb )
230 :     #
231 :     #-------------------------------------------------------------------------------
232 :     #
233 :     # Internal function to get RGB from validated hue and saturation:
234 :     #
235 :    
236 :     sub hs2rgb
237 :     {
238 :     my ( $h, $s ) = @_;
239 :     my $h6 = 6 * ( $h - floor($h) ); # Hue is cyclic modulo 1
240 :     my $m = 1 - $s;
241 :     map { $_ * $s + $m } ( $h6 <= 3 ) ? ( ( $h6 <= 1 ) ? ( 1, $h6, 0 )
242 :     : ( $h6 <= 2 ) ? ( 2-$h6, 1, 0 )
243 :     : ( 0, 1, $h6-2 )
244 :     )
245 :     : ( ( $h6 <= 4 ) ? ( 0, 4-$h6, 1 )
246 :     : ( $h6 <= 5 ) ? ( $h6-4, 0, 1 )
247 :     : ( 1, 0, 6-$h6 )
248 :     );
249 :     }
250 :    
251 :    
252 :     sub hsb2rgb
253 :     {
254 :     my ( $h, $s, $br ) = $_[0] && ref( $_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
255 :     make_zero2one( $h, $s, $br );
256 :     my @rgb = map { $_ * $br } hs2rgb( $h, $s );
257 :     wantarray() ? @rgb : \@rgb;
258 :     }
259 :    
260 :    
261 :     sub hsy2rgb
262 :     {
263 :     my ( $h, $s, $y ) = $_[0] && ref( $_[0] ) eq 'ARRAY' ? @{$_[0]} : @_;
264 :     make_zero2one( $h, $s, $y );
265 :    
266 :     my ( $r, $g, $b ) = hs2rgb( $h, $s );
267 :     my $luma = rgb2gray0( $r, $g, $b ); # How bright is the color?
268 :    
269 :     my @rgb;
270 :     if ( $luma < $y ) # Too dim without decreasing saturation
271 :     {
272 :     my $s = ( 1 - $y ) / ( 1 - $luma ) ;
273 :     my $m = 1 - $s;
274 :     @rgb = map { $_ * $s + $m } ( $r, $g, $b );
275 :     }
276 :     else # Too bright
277 :     {
278 :     my $k = $y / $luma;
279 :     @rgb = map { $_ * $k } ( $r, $g, $b );
280 :     }
281 :    
282 :     wantarray() ? @rgb : \@rgb;
283 :     }
284 :    
285 :    
286 :     #
287 :     # Internal function for finding HSB from validated RGB
288 :     #
289 :    
290 :     sub rgb2hsb0
291 :     {
292 :     my ( $min, undef, $br ) = sort { $a <=> $b } @_;
293 :     if ( $br == $min ) { return wantarray ? ( 0, 0, $br ) : [ 0, 0, $br ] }
294 :    
295 :     my ( $r, $g, $b ) = @_;
296 :     my $s_br = $br - $min; # $s * $br
297 :     my $h6;
298 :    
299 :     if ( $r == $br ) { $h6 = ( $b > $g ) ? 6 - ($b-$g)/$s_br : ($g-$b)/$s_br }
300 :     elsif ( $g == $br ) { $h6 = 2 + ($b-$r)/$s_br }
301 :     else { $h6 = 4 + ($r-$g)/$s_br }
302 :    
303 :     ( $h6/6, $s_br/$br, $br );
304 :     }
305 :    
306 :    
307 :     sub rgb2hsb
308 :     {
309 :     my ( $r, $g, $b ) = $_[0] && ref( $_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
310 :     make_zero2one( $r, $g, $b );
311 :    
312 :     my @hsb = rgb2hsb0( $r, $g, $b );
313 :    
314 :     wantarray ? @hsb : \@hsb;
315 :     }
316 :    
317 :    
318 :     sub rgb2hsy
319 :     {
320 :     my ( $r, $g, $b ) = $_[0] && ref( $_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
321 :     make_zero2one( $r, $g, $b );
322 :    
323 :     my @hsy = rgb2hsb0( $r, $g, $b );
324 :     $hsy[2] = rgb2gray0( $r, $g, $b );
325 :    
326 :     wantarray() ? @hsy : \@hsy;
327 :     }
328 :    
329 :    
330 :     #===============================================================================
331 :     # Conversions between linear RGB and CMY and CMYK values.
332 :     #
333 :     # @rgb = cmy2rgb( @cmy )
334 :     # @rgb = cmyk2rgb( @cmyk )
335 :     # @cmy = rgb2cym( @rgb )
336 :     # @cmyk = rgb2cymk( @rgb )
337 :     #
338 :     #-------------------------------------------------------------------------------
339 :    
340 :     sub cmy2rgb
341 :     {
342 :     my ( $c, $m, $y ) = $_[0] && ref( $_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
343 :     make_zero2one( $c, $m, $y );
344 :     my @rgb = ( 1 - $c, 1 - $m, 1 - $y );
345 :     wantarray() ? @rgb : \@rgb;
346 :     }
347 :    
348 :    
349 :     sub cmyk2rgb
350 :     {
351 :     my ( $c, $m, $y, $k ) = $_[0] && ref( $_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
352 :     make_zero2one( $c, $m, $y, $k );
353 :     my $br = 1 - $k;
354 : overbeek 1.1 my @rgb = ( ( 1 - $c ) * $br, ( 1 - $m ) * $br, ( 1 - $y ) * $br );
355 : golsen 1.7 wantarray() ? @rgb : \@rgb;
356 :     }
357 :    
358 :    
359 :     sub rgb2cmy
360 :     {
361 :     my ( $r, $g, $b ) = $_[0] && ref( $_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
362 :     make_zero2one( $r, $g, $b );
363 :     my @cmy = ( 1 - $r, 1 - $g, 1 - $b );
364 :     wantarray() ? @cmy : \@cmy;
365 : overbeek 1.1 }
366 :    
367 : golsen 1.7
368 :     sub rgb2cmyk
369 :     {
370 :     my ( $r, $g, $b ) = $_[0] && ref( $_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
371 :     make_zero2one( $r, $g, $b );
372 :     my $br = $r > $g ? ( $r > $b ? $r : $b ) : ( $g > $b ? $g : $b );
373 :     my @cmyk = $br > 0 ? ( 1 - $r/$br, 1 - $g/$br, 1 - $b/$br, 1 - $br )
374 :     : ( 0, 0, 0, 1 );
375 :     wantarray() ? @cmyk : \@cmyk;
376 :     }
377 : overbeek 1.1
378 :    
379 : golsen 1.7 #===============================================================================
380 :     # Conversions between linear RGB and gray (luma) values.
381 :     #-------------------------------------------------------------------------------
382 :     #
383 :     # Various ITU recommendations and the new standard:
384 :     # 0.299 * $r + 0.587 * $g + 0.114 * $b; # Rec 601-1 (NTSC)
385 :     # 0.213 * $r + 0.715 * $g + 0.072 * $b; # Rec 709 (sRGB)
386 :     # 0.222 * $r + 0.707 * $g + 0.071 * $b; # ITU std (D65 white point)
387 :     # 0.330 * $r + 0.590 * $g + 0.080 * $b; # GJO
388 :     #
389 :     #-------------------------------------------------------------------------------
390 :     #
391 :     # Internal function for gray (=luma) from validated RGB:
392 :     #
393 :     sub rgb2gray0
394 :     {
395 :     my ( $r, $g, $b ) = @_;
396 : overbeek 1.1
397 : golsen 1.7 0.213 * $r + 0.715 * $g + 0.072 * $b; # Rec 709 (sRGB)
398 : overbeek 1.1 }
399 :    
400 :    
401 : golsen 1.7 #-------------------------------------------------------------------------------
402 : overbeek 1.1 # Produce the gray equivalent in brightness to an RGB value:
403 : golsen 1.7 #
404 :     # $gray = rgb2gray( @rgb )
405 :     # @rgb = gray2rgb( $gray )
406 :     #
407 :     #-------------------------------------------------------------------------------
408 :    
409 :     sub rgb2gray
410 :     {
411 :     my ( $r, $g, $b ) = $_[0] && ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
412 :     make_zero2one( $r, $g, $b );
413 :     rgb2gray0( $r, $g, $b );
414 :     }
415 : overbeek 1.1
416 : golsen 1.7
417 :     sub gray2rgb
418 :     {
419 :     my $gray = zero2one( $_[0] );
420 :     my @rgb = ( $gray, $gray, $gray );
421 :     wantarray ? @rgb : \@rgb;
422 : overbeek 1.1 }
423 :    
424 :    
425 : golsen 1.7 #===============================================================================
426 :     # Conversions amongst RGB values, HTML hex code values, and color names.
427 :     #-------------------------------------------------------------------------------
428 :     #
429 :     # Named colors in HTML and SVG specifications.
430 :     # Beware that this copy has mixed case names.
431 :     #
432 :     my %name2html =
433 :     ( AliceBlue => '#F0F8FF', # SVG 1.0
434 :     AntiqueWhite => '#FAEBD7', # SVG 1.0
435 :     Aqua => '#00FFFF', # CSS 3.0
436 :     Aquamarine => '#7FFFD4', # SVG 1.0
437 :     Azure => '#F0FFFF', # SVG 1.0
438 :     Beige => '#F5F5DC', # SVG 1.0
439 :     Bisque => '#FFE4C4', # SVG 1.0
440 :     Black => '#000000', # CSS 3.0
441 :     BlanchedAlmond => '#FFEBCD', # SVG 1.0
442 :     Blue => '#0000FF', # CSS 3.0
443 :     BlueViolet => '#8A2BE2', # SVG 1.0
444 :     Brown => '#A52A2A', # SVG 1.0
445 :     Burlywood => '#DEB887', # SVG 1.0
446 :     CadetBlue => '#5F9EA0', # SVG 1.0
447 :     Chartreuse => '#7FFF00', # SVG 1.0
448 :     Chocolate => '#D2691E', # SVG 1.0
449 :     Coral => '#FF7F50', # SVG 1.0
450 :     CornflowerBlue => '#6495ED', # SVG 1.0
451 :     Cornsilk => '#FFF8DC', # SVG 1.0
452 :     Crimson => '#DC143C', # SVG 1.0
453 :     Cyan => '#00FFFF', # SVG 1.0 = Teal
454 :     DarkBlue => '#00008B', # SVG 1.0
455 :     DarkCyan => '#008B8B', # SVG 1.0
456 :     DarkGoldenrod => '#B8860B', # SVG 1.0
457 :     DarkGray => '#A9A9A9', # SVG 1.0
458 :     DarkGreen => '#006400', # SVG 1.0
459 :     DarkKhaki => '#BDB76B', # SVG 1.0
460 :     DarkMagenta => '#8B008B', # SVG 1.0
461 :     DarkOliveGreen => '#556B2F', # SVG 1.0
462 :     Darkorange => '#FF8C00', # SVG 1.0
463 :     DarkOrchid => '#9932CC', # SVG 1.0
464 :     DarkRed => '#8B0000', # SVG 1.0
465 :     DarkSalmon => '#E9967A', # SVG 1.0
466 :     DarkSeaGreen => '#8FBC8F', # SVG 1.0
467 :     DarkSlateBlue => '#483D8B', # SVG 1.0
468 :     DarkSlateGray => '#2F4F4F', # SVG 1.0
469 :     DarkTurquoise => '#00CED1', # SVG 1.0
470 :     DarkViolet => '#9400D3', # SVG 1.0
471 :     DeepPink => '#FF1493', # SVG 1.0
472 :     DeepSkyBlue => '#00BFFF', # SVG 1.0
473 :     DimGray => '#696969', # SVG 1.0
474 :     Dimgrey => '#696969', # SVG 1.0
475 :     DodgerBlue => '#1E90FF', # SVG 1.0
476 :     FireBrick => '#B22222', # SVG 1.0
477 :     FloralWhite => '#FFFAF0', # SVG 1.0
478 :     ForestGreen => '#228B22', # SVG 1.0
479 :     Fuchsia => '#FF00FF', # CSS 3.0 = Magenta
480 :     Gainsboro => '#DCDCDC', # SVG 1.0
481 :     GhostWhite => '#F8F8FF', # SVG 1.0
482 :     Gold => '#FFD700', # SVG 1.0
483 :     Goldenrod => '#DAA520', # SVG 1.0
484 :     Gray => '#808080', # CSS 3.0
485 :     Green => '#008000', # CSS 3.0
486 :     GreenYellow => '#ADFF2F', # SVG 1.0
487 :     Grey => '#808080', # SVG 1.0
488 :     Honeydew => '#F0FFF0', # SVG 1.0
489 :     HotPink => '#FF69B4', # SVG 1.0
490 :     IndianRed => '#CD5C5C', # SVG 1.0
491 :     Indigo => '#4B0082', # SVG 1.0
492 :     Ivory => '#FFFFF0', # SVG 1.0
493 :     Khaki => '#F0E68C', # SVG 1.0
494 :     Lavender => '#E6E6FA', # SVG 1.0
495 :     LavenderBlush => '#FFF0F5', # SVG 1.0
496 :     LawnGreen => '#7CFC00', # SVG 1.0
497 :     LemonChiffon => '#FFFACD', # SVG 1.0
498 :     LightBlue => '#ADD8E6', # SVG 1.0
499 :     LightCoral => '#F08080', # SVG 1.0
500 :     LightCyan => '#E0FFFF', # SVG 1.0
501 :     LightGoldenrodYellow => '#FAFAD2', # SVG 1.0
502 :     LightGray => '#D3D3D3', # SVG 1.0
503 :     LightGreen => '#90EE90', # SVG 1.0
504 :     LightPink => '#FFB6C1', # SVG 1.0
505 :     LightSalmon => '#FFA07A', # SVG 1.0
506 :     LightSeaGreen => '#20B2AA', # SVG 1.0
507 :     LightSkyBlue => '#87CEFA', # SVG 1.0
508 :     LightSlateGray => '#778899', # SVG 1.0
509 :     LightSteelBlue => '#B0C4DE', # SVG 1.0
510 :     LightYellow => '#FFFFE0', # SVG 1.0
511 :     Lime => '#00FF00', # CSS 3.0
512 :     LimeGreen => '#32CD32', # SVG 1.0
513 :     Linen => '#FAF0E6', # SVG 1.0
514 :     Magenta => '#FF00FF', # SVG 1.0 = Fuchsia
515 :     Maroon => '#800000', # CSS 3.0
516 :     MediumAquamarine => '#66CDAA', # SVG 1.0
517 :     MediumBlue => '#0000CD', # SVG 1.0
518 :     MediumOrchid => '#BA55D3', # SVG 1.0
519 :     MediumPurple => '#9370DB', # SVG 1.0
520 :     MediumSeaGreen => '#3CB371', # SVG 1.0
521 :     MediumSlateBlue => '#7B68EE', # SVG 1.0
522 :     MediumSpringGreen => '#00FA9A', # SVG 1.0
523 :     MediumTurquoise => '#48D1CC', # SVG 1.0
524 :     MediumVioletRed => '#C71585', # SVG 1.0
525 :     MidnightBlue => '#191970', # SVG 1.0
526 :     MintCream => '#F5FFFA', # SVG 1.0
527 :     MistyRose => '#FFE4E1', # SVG 1.0
528 :     Moccasin => '#FFE4B5', # SVG 1.0
529 :     NavajoWhite => '#FFDEAD', # SVG 1.0
530 :     Navy => '#000080', # CSS 3.0
531 :     OldLace => '#FDF5E6', # SVG 1.0
532 :     Olive => '#808000', # CSS 3.0
533 :     OliveDrab => '#6B8E23', # SVG 1.0
534 :     Orange => '#FFA500', # SVG 1.0
535 :     OrangeRed => '#FF4500', # SVG 1.0
536 :     Orchid => '#DA70D6', # SVG 1.0
537 :     PaleGoldenrod => '#EEE8AA', # SVG 1.0
538 :     PaleGreen => '#98FB98', # SVG 1.0
539 :     PaleTurquoise => '#AFEEEE', # SVG 1.0
540 :     PaleVioletRed => '#DB7093', # SVG 1.0
541 :     PapayaWhip => '#FFEFD5', # SVG 1.0
542 :     PeachPuff => '#FFDAB9', # SVG 1.0
543 :     Peru => '#CD853F', # SVG 1.0
544 :     Pink => '#FFC0CB', # SVG 1.0
545 :     Plum => '#DDA0DD', # SVG 1.0
546 :     PowderBlue => '#B0E0E6', # SVG 1.0
547 :     Purple => '#800080', # CSS 3.0
548 :     Red => '#FF0000', # CSS 3.0
549 :     RosyBrown => '#BC8F8F', # SVG 1.0
550 :     RoyalBlue => '#4169E1', # SVG 1.0
551 :     SaddleBrown => '#8B4513', # SVG 1.0
552 :     Salmon => '#FA8072', # SVG 1.0
553 :     SandyBrown => '#F4A460', # SVG 1.0
554 :     SeaGreen => '#2E8B57', # SVG 1.0
555 :     Seashell => '#FFF5EE', # SVG 1.0
556 :     Sienna => '#A0522D', # SVG 1.0
557 :     Silver => '#C0C0C0', # CSS 3.0
558 :     SkyBlue => '#87CEEB', # SVG 1.0
559 :     SlateBlue => '#6A5ACD', # SVG 1.0
560 :     SlateGray => '#708090', # SVG 1.0
561 :     Snow => '#FFFAFA', # SVG 1.0
562 :     SpringGreen => '#00FF7F', # SVG 1.0
563 :     SteelBlue => '#4682B4', # SVG 1.0
564 :     Tan => '#D2B48C', # SVG 1.0
565 :     Teal => '#008080', # CSS 3.0 = Cyan
566 :     Teal => '#008080', # SVG 1.0
567 :     Thistle => '#D8BFD8', # SVG 1.0
568 :     Tomato => '#FF6347', # SVG 1.0
569 :     Turquoise => '#40E0D0', # SVG 1.0
570 :     Violet => '#EE82EE', # SVG 1.0
571 :     Wheat => '#F5DEB3', # SVG 1.0
572 :     White => '#FFFFFF', # CSS 3.0
573 :     WhiteSmoke => '#F5F5F5', # SVG 1.0
574 :     Yellow => '#FFFF00', # CSS 3.0
575 :     YellowGreen => '#9ACD32', # SVG 1.0
576 :     );
577 :    
578 :     #
579 :     # Additional color names for grays and anything else we might want to
580 :     # recognize.
581 :     #
582 :    
583 :     my %name2html_too =
584 :     ( Gray0 => '#000000',
585 :     Gray1 => '#030303',
586 :     Gray2 => '#050505',
587 :     Gray3 => '#080808',
588 :     Gray4 => '#0a0a0a',
589 :     Gray5 => '#0d0d0d',
590 :     Gray6 => '#0f0f0f',
591 :     Gray7 => '#121212',
592 :     Gray8 => '#141414',
593 :     Gray9 => '#171717',
594 :     Gray10 => '#1a1a1a',
595 :     Gray11 => '#1c1c1c',
596 :     Gray12 => '#1f1f1f',
597 :     Gray13 => '#212121',
598 :     Gray14 => '#242424',
599 :     Gray15 => '#262626',
600 :     Gray16 => '#292929',
601 :     Gray17 => '#2b2b2b',
602 :     Gray18 => '#2e2e2e',
603 :     Gray19 => '#303030',
604 :     Gray20 => '#333333',
605 :     Gray21 => '#363636',
606 :     Gray22 => '#383838',
607 :     Gray23 => '#3b3b3b',
608 :     Gray24 => '#3d3d3d',
609 :     Gray25 => '#404040',
610 :     Gray26 => '#424242',
611 :     Gray27 => '#454545',
612 :     Gray28 => '#474747',
613 :     Gray29 => '#4a4a4a',
614 :     Gray30 => '#4d4d4d',
615 :     Gray31 => '#4f4f4f',
616 :     Gray32 => '#525252',
617 :     Gray33 => '#545454',
618 :     Gray34 => '#575757',
619 :     Gray35 => '#595959',
620 :     Gray36 => '#5c5c5c',
621 :     Gray37 => '#5e5e5e',
622 :     Gray38 => '#616161',
623 :     Gray39 => '#636363',
624 :     Gray40 => '#666666',
625 :     Gray41 => '#696969',
626 :     Gray42 => '#6b6b6b',
627 :     Gray43 => '#6e6e6e',
628 :     Gray44 => '#707070',
629 :     Gray45 => '#737373',
630 :     Gray46 => '#757575',
631 :     Gray47 => '#787878',
632 :     Gray48 => '#7a7a7a',
633 :     Gray49 => '#7d7d7d',
634 :     Gray50 => '#7f7f7f',
635 :     Gray51 => '#828282',
636 :     Gray52 => '#858585',
637 :     Gray53 => '#878787',
638 :     Gray54 => '#8a8a8a',
639 :     Gray55 => '#8c8c8c',
640 :     Gray56 => '#8f8f8f',
641 :     Gray57 => '#919191',
642 :     Gray58 => '#949494',
643 :     Gray59 => '#969696',
644 :     Gray60 => '#999999',
645 :     Gray61 => '#9c9c9c',
646 :     Gray62 => '#9e9e9e',
647 :     Gray63 => '#a1a1a1',
648 :     Gray64 => '#a3a3a3',
649 :     Gray65 => '#a6a6a6',
650 :     Gray66 => '#a8a8a8',
651 :     Gray67 => '#ababab',
652 :     Gray68 => '#adadad',
653 :     Gray69 => '#b0b0b0',
654 :     Gray70 => '#b3b3b3',
655 :     Gray71 => '#b5b5b5',
656 :     Gray72 => '#b8b8b8',
657 :     Gray73 => '#bababa',
658 :     Gray74 => '#bdbdbd',
659 :     Gray75 => '#bfbfbf',
660 :     Gray76 => '#c2c2c2',
661 :     Gray77 => '#c4c4c4',
662 :     Gray78 => '#c7c7c7',
663 :     Gray79 => '#c9c9c9',
664 :     Gray80 => '#cccccc',
665 :     Gray81 => '#cfcfcf',
666 :     Gray82 => '#d1d1d1',
667 :     Gray83 => '#d4d4d4',
668 :     Gray84 => '#d6d6d6',
669 :     Gray85 => '#d9d9d9',
670 :     Gray86 => '#dbdbdb',
671 :     Gray87 => '#dedede',
672 :     Gray88 => '#e0e0e0',
673 :     Gray89 => '#e3e3e3',
674 :     Gray90 => '#e5e5e5',
675 :     Gray91 => '#e8e8e8',
676 :     Gray92 => '#ebebeb',
677 :     Gray93 => '#ededed',
678 :     Gray94 => '#f0f0f0',
679 :     Gray95 => '#f2f2f2',
680 :     Gray96 => '#f5f5f5',
681 :     Gray97 => '#f7f7f7',
682 :     Gray98 => '#fafafa',
683 :     Gray99 => '#fcfcfc',
684 :     Gray100 => '#ffffff',
685 :    
686 :     # And just for fun:
687 :    
688 :     IllinoisBlue => '#003C7D',
689 :     IllinoisFormalBlue => '#6EBBBF',
690 :     IllinoisFormalOrange => '#EF8A1C',
691 :     IllinoisOrange => '#F47F24',
692 :     UIBlue => '#003C7D',
693 :     UIFormalBlue => '#6EBBBF',
694 :     UIFormalOrange => '#EF8A1C',
695 :     UIOrange => '#F47F24',
696 :     );
697 :    
698 :     # Version with pretty names, used for RGB to name:
699 :    
700 :     my @name2rgb = map { [ $_ => htmlhex2rgb( $name2html{ $_ } ) ] } keys %name2html;
701 :    
702 :     # Version with lowercase names, used for name to RGB (includes nonstandard
703 :     # names):
704 :    
705 :     my %lc_name2rgb = ( ( map { lc( $_->[0] ) => $_->[1] } @name2rgb ),
706 :     ( map { lc( $_ ) => htmlhex2rgb( $name2html_too{ $_ } ) } keys %name2html_too )
707 :     );
708 :    
709 :     #-------------------------------------------------------------------------------
710 :     # Convert html to RGB and sRGB:
711 :     #
712 :     # @rgb = html2rgb( $htmlcolor )
713 :     #
714 :     # where $htmlcolor is:
715 :     #
716 :     # namedcolor or #xxxxxx or #xxx or xxxxxx or xxx
717 :     #
718 :     #-------------------------------------------------------------------------------
719 :     #
720 :     # Internal function for converting html sRGB hex strings to RGB values.
721 :     # It will take 3 or 6 hexadecimal digits, with or without a leading #.
722 :     #
723 :     sub htmlhex2rgb
724 :     {
725 :     local $_ = $_[0] || '';
726 :     my @hex_rgb = m/^#?([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])$/i ? ( $1, $2, $3 )
727 :     : m/^#?([\da-f])([\da-f])([\da-f])$/i ? map { "$_$_" } ( $1, $2, $3 )
728 :     : ( '00', '00', '00' );
729 : overbeek 1.1
730 : golsen 1.7 [ map { $index2rgb[ hex( $_ ) ] } @hex_rgb ];
731 : overbeek 1.1 }
732 :    
733 :    
734 : golsen 1.7 sub html2rgb
735 :     {
736 :     my $html = lc ( shift || '' ); # Only lower case is indexed
737 :     $html =~ s/\s+//g; # No spaces
738 :     $html =~ s/grey/gray/g; # Only USA spelling is indexed
739 :    
740 :     my $rgb = $lc_name2rgb{ $html } || htmlhex2rgb( $html );
741 : golsen 1.4
742 : golsen 1.7 wantarray ? @$rgb : $rgb;
743 : golsen 1.4 }
744 :    
745 :    
746 : overbeek 1.1 #-------------------------------------------------------------------------------
747 : golsen 1.7 # Convert an RGB and gray values to sRGB HTML strings
748 :     #
749 :     # $html = rgb2html( @rgb ) # linear RGB to sRGB html
750 :     # $html = rgb2html_g10( @rgb ) # gamma = 1.0, or @rgb is sRGB
751 :     # $html = rgb2html_g18( @rgb ) # gamma = 1.8
752 :     # $html = rgb2html_g22( @rgb ) # gamma = 2.2
753 :     # $html = gray2html( $gray ) # linear gray to sRGB html
754 :     # $html = gray2html_g10( $gray ) # gamma = 1.0
755 :     # $html = gray2html_g18( $gray ) # gamma = 1.8
756 :     # $html = gray2html_g22( $gray ) # gamma = 2.2
757 :     #
758 :     #-------------------------------------------------------------------------------
759 :     #
760 :     # Internal routine to format string:
761 : overbeek 1.1 #
762 : golsen 1.7 sub srgb2html0
763 :     {
764 :     sprintf( '#%02x%02x%02x', map { int( 255.999 * $_ ) } @_ );
765 :     }
766 :    
767 :    
768 :     #-------------------------------------------------------------------------------
769 :     # Convert an RGB value to an HTML string:
770 : overbeek 1.1 #-------------------------------------------------------------------------------
771 : golsen 1.7 sub rgb2html
772 :     {
773 :     my ( $r, $g, $b ) = defined($_[0]) && ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
774 :     make_zero2one( $r, $b, $b );
775 :     srgb2html0( linear2srgb( $r, $g, $b ) );
776 :     }
777 :    
778 :     #
779 :     # RGB to HTML, with gamma adjustment. This should normally be done using
780 :     # the sRGB correction invoked by rgb2html(). g10 (gamma 1.0) writes
781 :     # unadjusted RGB values, so it would be appropriate for:
782 :     #
783 :     # $html = rgb2html_g10( @sRGB ).
784 :     #
785 :     # gamma = 1.0
786 :     #
787 :     sub rgb2html_g10
788 :     {
789 :     my ( $r, $g, $b ) = defined($_[0]) && ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
790 :     srgb2html0( map { zero2one($_) } ( $r, $g, $b ) );
791 :     }
792 :    
793 :     #
794 :     # gamma = 1.8
795 :     #
796 :     sub rgb2html_g18
797 :     {
798 :     my ( $r, $g, $b ) = defined($_[0]) && ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
799 :     srgb2html0( map { zero2one($_) ** (1/1.8) } ( $r, $g, $b ) );
800 :     }
801 :    
802 :     #
803 :     # gamma = 2.2
804 :     #
805 :     sub rgb2html_g22
806 :     {
807 :     my ( $r, $g, $b ) = defined($_[0]) && ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_;
808 :     srgb2html0( map { zero2one($_) ** (1/2.2) } ( $r, $g, $b ) );
809 :     }
810 :    
811 :    
812 :     #-------------------------------------------------------------------------------
813 :     # Convert an gray value to an HTML string.
814 :     #-------------------------------------------------------------------------------
815 :     sub gray2html
816 :     {
817 :     my $gray = linear2srgb( zero2one( $_[0] ) );
818 :     srgb2html0( $gray, $gray, $gray );
819 :     }
820 :    
821 :    
822 :     #
823 :     # gray to HTML, with gamma adjustment. This should normally be done using
824 :     # the sRGB correction invoked by gray2html().
825 :     #
826 :     # gamma = 1.0
827 :     #
828 :     sub gray2html_g10
829 :     {
830 :     my $gray = zero2one( $_[0] );
831 :     srgb2html0( $gray, $gray, $gray );
832 :     }
833 :    
834 :     #
835 :     # gamma = 1.8
836 :     #
837 :     sub gray2html_g18
838 :     {
839 :     my $gray = zero2one( $_[0] ) ** 1.8;
840 :     srgb2html0( $gray, $gray, $gray );
841 :     }
842 :    
843 :     #
844 :     # gamma = 2.2
845 :     #
846 :     sub gray2html_g22
847 : overbeek 1.1 {
848 : golsen 1.7 my $gray = zero2one( $_[0] ) ** 2.2;
849 :     srgb2html0( $gray, $gray, $gray );
850 : overbeek 1.1 }
851 :    
852 :    
853 :     #-------------------------------------------------------------------------------
854 : golsen 1.7 # Find the closest named color from CSS 3.0 and SVG 1.0:
855 :     #
856 :     # $name = rgb2name( @rgb )
857 : overbeek 1.1 #
858 :     #-------------------------------------------------------------------------------
859 : golsen 1.7 sub rgb2name
860 : overbeek 1.1 {
861 : golsen 1.7 my ( $r, $g, $b ) = ref( $_[0] ) eq 'ARRAY' ? @{ $_[0] } : @_;
862 :     make_zero2one( $r, $g, $b );
863 :    
864 :     my $rgb = [ $r, $g, $b ];
865 :     my ( $name, $dmin ) = ( '', 3 );
866 :     foreach ( @name2rgb )
867 : overbeek 1.1 {
868 : golsen 1.7 my $d = rgb_distance( $rgb, $_->[1] );
869 :     if ( $d < $dmin ) { $name = $_->[0]; $dmin = $d; }
870 : overbeek 1.1 }
871 :    
872 : golsen 1.7 $name;
873 :     }
874 :    
875 :    
876 :     #
877 :     # Internal function defining a distance between 2 rgb colors
878 :     #
879 :     # $distance = rgb_distance( $rgb1, $rgb2 )
880 :     #
881 :     sub rgb_distance
882 :     {
883 :     my ( $r1, $g1, $b1 ) = $_[0] && ( ref( $_[0] ) eq 'ARRAY' ) ? @{$_[0]} : (0,0,0);
884 :     my ( $r2, $g2, $b2 ) = $_[1] && ( ref( $_[1] ) eq 'ARRAY' ) ? @{$_[1]} : (0,0,0);
885 :    
886 :     make_zero2one( $r1, $g1, $b1 );
887 :     make_zero2one( $r2, $g2, $b2 );
888 :    
889 :     abs( $r1 - $r2 ) + abs( $g1 - $g2 ) + abs( $b1 - $b2 );
890 : overbeek 1.1 }
891 :    
892 :    
893 : golsen 1.7 #===============================================================================
894 :     # A few other functions.
895 : overbeek 1.1 #-------------------------------------------------------------------------------
896 : golsen 1.7 # Blend 2 or more RGB colors (actually takes any triplets):
897 :     #
898 :     # \@color = blend_rgb_colors( $color1, $color2, ... )
899 :     # @color = blend_rgb_colors( $color1, $color2, ... )
900 : overbeek 1.1 #
901 :     #-------------------------------------------------------------------------------
902 : golsen 1.7 sub blend_rgb_colors
903 : overbeek 1.1 {
904 : golsen 1.7 my @rgb = ( 0, 0, 0 );
905 :     foreach ( @_ )
906 :     {
907 :     next if ! ( $_ && ( ref($_) eq 'ARRAY' ) && ( @$_ >= 3 ) ); # Skip bad colors
908 :     my @clr = map { zero2one( $_ ) } @$_;
909 :     foreach ( @rgb ) { $_ += shift @clr }
910 :     }
911 :     if ( @_ ) { foreach ( @rgb ) { $_ /= @_ } }
912 :    
913 :     wantarray() ? @rgb : \@rgb;
914 : overbeek 1.1 }
915 :    
916 :    
917 :     #-------------------------------------------------------------------------------
918 : golsen 1.7 # Blend 2 or more HTML colors (in linear RGB space)
919 :     #
920 :     # $html = blend_html_colors( $color1, $color2, ... )
921 : overbeek 1.1 #
922 :     #-------------------------------------------------------------------------------
923 : golsen 1.7 sub blend_html_colors
924 : overbeek 1.1 {
925 : golsen 1.7 @_ or return '#000000';
926 :    
927 :     my @rgb = ( 0, 0, 0 );
928 :     foreach ( @_ )
929 :     {
930 :     my @clr = html2rgb( $_ );
931 :     foreach ( @rgb ) { $_ += shift @clr }
932 :     }
933 :     foreach ( @rgb ) { $_ /= @_ }
934 : overbeek 1.1
935 : golsen 1.7 rgb2html( @rgb );
936 : overbeek 1.1 }
937 :    
938 :    
939 :     1;

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3