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

View of /FigKernelPackages/gjocolorlib.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (download) (as text) (annotate)
Tue Jun 23 01:53:37 2009 UTC (10 years, 9 months ago) by golsen
Branch: MAIN
Changes since 1.1: +1 -1 lines
Fix a typo in a color name.

package gjocolorlib;

use strict;
eval { use Data::Dumper };

#  Invoke with:
#
#      use gjocolorlib;
#
#  Based on component values from 0 to 1:
#
#     $rgb  = [ $red, $green, $blue ]
#     $hsb  = [ $hue, $saturation, $brightness ]
#     $cmy  = [ $cyan, $magenta, $yellow ]
#     $cmyk = [ $cyan, $magenta, $yellow, $black ]

#  Exported functions:
#
#     $rgb  = hsb2rgb( $hsb )
#     @rgb  = hsb2rgb( @hsb )
#     $rgb  = cmy2rgb( $cmy )
#     @rgb  = cmy2rgb( @cmy )
#     $rgb  = cmyk2rgb( $cmyk )
#     @rgb  = cmyk2rgb( @cmyk )
#     $rgb  = html2rgb( $html )
#     @rgb  = html2rgb( $html )
#     $gray = rgb2gray( $rgb )
#     $gray = rgb2gray( @rgb )
#     $html = rgb2html( $rgb )
#     $html = rgb2html( @rgb )
#     $name = rgb2name( $rgb )
#     $name = rgb2name( @rgb )
#
#     $rgb  = blend_rgb_colors( $color1, $color2, ... )
#     @rgb  = blend_rgb_colors( $color1, $color2, ... )
#     $html = blend_html_colors( $color1, $color2, ... )


require Exporter;

our @ISA = qw(Exporter);
our @EXPORT = qw(
        hsb2rgb
        cmy2rgb
        cmyk2rgb
        html2rgb
        rgb2gray
        rgb2html
        rgb2name
        blend_rgb_colors
        blend_html_colors
        );
our @EXPORT_OK = qw(
        UI_Orange
        UI_Formal_Orange
        UI_Blue
        UI_Formal_Blue
        );


my $UI_Orange        = [       1, 102/255,       0 ];
my $UI_Formal_Orange = [ 204/255, 102/255,       0 ];
my $UI_Blue          = [       0,  51/255, 102/255 ];
my $UI_Formal_Blue   = [  51/255,  51/255, 102/255 ];

sub floor {
    my $x = $_[0];
    defined( $x ) || return undef;
    ( $x >= 0 ) || ( int($x) == $x ) ? int( $x ) : -1 - int( - $x )
}
sub min { my ( $a, $b ) = @_; ( $a < $b ) ? $a : $b }
sub max { my ( $a, $b ) = @_; ( $a > $b ) ? $a : $b }


#  Convert HSB to RGB:
#  Here, hue is taken to be in range 0 - 1;
#  It is sometimes 0 - 6 and sometimes 0 - 2*pi

sub hsb2rgb {
    my ( $h, $s, $br ) = @_;
    if ( ref( $h ) eq "ARRAY" ) { ( $h, $s, $br ) = @$h }
    defined( $h ) && defined( $s ) && defined( $br ) || return undef;

    $h = 6 * ($h - floor($h));      # Hue is made cyclic modulo 1
    if ( $s  > 1 ) { $s  = 1 } elsif ( $s  < 0 ) { $s  = 0 }  # 0 <= s  <= 1
    if ( $br > 1 ) { $br = 1 } elsif ( $br < 0 ) { $br = 0 }  # 0 <= br <= 1
    my ( $r, $g, $b ) = ( $h <= 3 ) ? ( ( $h <= 1 ) ? ( 1,      $h,     0      )
                                      : ( $h <= 2 ) ? ( 2 - $h, 1,      0      )
                                      :               ( 0,      1,      $h - 2 )
                                      )
                                    : ( ( $h <= 4 ) ? ( 0,      4 - $h, 1      )
                                      : ( $h <= 5 ) ? ( $h - 4, 0,      1      )
                                      :               ( 1,      0,      6 - $h )
                                      );
    my @rgb = ( ( $r * $s + 1 - $s ) * $br,
                ( $g * $s + 1 - $s ) * $br,
                ( $b * $s + 1 - $s ) * $br
              );
    wantarray() ? @rgb : \@rgb
}


#  Convert CMY to RGB:

sub cmy2rgb {
    my ( $c, $m, $y ) = @_;
    if ( ref( $c ) eq "ARRAY" ) { ( $c, $m, $y ) = @$c }
    defined( $c ) && defined( $m ) && defined( $y ) || return undef;
    if ( $c > 1 ) { $c = 1 } elsif ( $c < 0 ) { $c = 0 }
    if ( $m > 1 ) { $m = 1 } elsif ( $m < 0 ) { $m = 0 }
    if ( $y > 1 ) { $y = 1 } elsif ( $y < 0 ) { $y = 0 }
    wantarray() ? ( 1 - $c, 1 - $m, 1 - $y ) : [ 1 - $c, 1 - $m, 1 - $y ]
}


#  Convert CMYK to RGB:

sub cmyk2rgb {
    my ( $c, $m, $y, $k ) = @_;
    if ( ref( $c ) eq "ARRAY" ) { ( $c, $m, $y, $k ) = @$c }
    defined( $c ) && defined( $m ) && defined( $y ) && defined( $k ) || return undef;
    if ( $c > 1 ) { $c = 1 } elsif ( $c < 0 ) { $c = 0 }
    if ( $m > 1 ) { $m = 1 } elsif ( $m < 0 ) { $m = 0 }
    if ( $y > 1 ) { $y = 1 } elsif ( $y < 0 ) { $y = 0 }
    my $br = ($k < 0) ? 1 : ($k > 1) ? 0 : 1 - $k;
    my @rgb = ( ( 1 - $c ) * $br, ( 1 - $m ) * $br, ( 1 - $y ) * $br );
    wantarray() ? @rgb : \@rgb
}

#  Named colors:

my %name2html = map { lc }
      ( Black => '#000000',
        Blue => '#0000FF',
        CadetBlue3 => '#77BFC7',
        CadetBlue4 => '#4C787E',
        Chartreuse => '#8AFB17',
        Chartreuse2 => '#7FE817',
        Chartreuse3 => '#6CC417',
        Chartreuse4 => '#437C17',
        Chocolate => '#C85A17',
        Coral => '#F76541',
        Coral2 => '#E55B3C',
        Coral3 => '#C34A2C',
        CornflowerBlue => '#151B8D',
        Cyan => '#00FFFF',
        Cyan1 => '#57FEFF',
        Cyan2 => '#50EBEC',
        Cyan3 => '#46C7C7',
        Cyan4 => '#307D7E',
        DarkGoldenrod => '#AF7817',
        DarkGoldenrod1 => '#FBB117',
        DarkGoldenrod2 => '#E8A317',
        DarkGoldenrod3 => '#C58917',
        DarkGoldenrod4 => '#7F5217',
        DarkGreen => '#254117',
        DarkOliveGreen1 => '#CCFB5D',
        DarkOliveGreen2 => '#BCE954',
        DarkOliveGreen3 => '#A0C544',
        DarkOliveGreen4 => '#667C26',
        DarkOrange => '#F88017',
        DarkOrange1 => '#F87217',
        DarkOrange2 => '#E56717',
        DarkOrange3 => '#7E3117',
        DarkOrange3 => '#C35617',
        DarkOrchid => '#7D1B7E',
        DarkOrchid1 => '#B041FF',
        DarkOrchid2 => '#A23BEC',
        DarkOrchid3 => '#8B31C7',
        DarkOrchid4 => '#571B7e',
        DarkSalmon => '#E18B6B',
        DarkSeaGreen => '#8BB381',
        DarkSeaGreen1 => '#C3FDB8',
        DarkSeaGreen2 => '#B5EAAA',
        DarkSeaGreen3 => '#99C68E',
        DarkSeaGreen4 => '#617C58',
        DarkSlateBlue => '#2B3856',
        DarkSlateGray => '#25383C',
        DarkSlateGray1 => '#9AFEFF',
        DarkSlateGray2 => '#8EEBEC',
        DarkSlateGray3 => '#78c7c7',
        DarkSlateGray4 => '#4C7D7E',
        DarkTurquoise => '#3B9C9C',
        DarkViolet => '#842DCE',
        DeepPink => '#F52887',
        DeepPink2 => '#E4287C',
        DeepPink3 => '#C12267',
        DeepPink4 => '#7D053F',
        DeepSkyBlue => '#3BB9FF',
        DeepSkyBlue2 => '#38ACEC',
        DeepSkyBlue3 => '#3090C7',
        DeepSkyBlue4 => '#25587E',
        DimGray => '#463E41',
        DodgerBlue => '#1589FF',
        DodgerBlue2 => '#157DEC',
        DodgerBlue3 => '#1569C7',
        DodgerBlue4 => '#153E7E',
        Firebrick => '#800517',
        Firebrick1 => '#F62817',
        Firebrick2 => '#E42217',
        Firebrick3 => '#C11B17',
        ForestGreen => '#4E9258',
        Gold => '#D4A017',
        Gold1 => '#FDD017',
        Gold2 => '#EAC117',
        Gold3 => '#C7A317',
        Gold4 => '#806517',
        Goldenrod => '#EDDA74',
        Goldenrod1 => '#FBB917',
        Goldenrod2 => '#E9AB17',
        Goldenrod3 => '#C68E17',
        Goldenrod4 => '#805817',
        Gray => '#736F6E',
        Gray0 => '#150517',
        Gray18 => '#250517',
        Gray21 => '#2B1B17',
        Gray23 => '#302217',
        Gray24 => '#302226',
        Gray25 => '#342826',
        Gray26 => '#34282C',
        Gray27 => '#382D2C',
        Gray28 => '#3b3131',
        Gray29 => '#3E3535',
        Gray30 => '#413839',
        Gray31 => '#41383C',
        Gray32 => '#463E3F',
        Gray34 => '#4A4344',
        Gray35 => '#4C4646',
        Gray36 => '#4E4848',
        Gray37 => '#504A4B',
        Gray38 => '#544E4F',
        Gray39 => '#565051',
        Gray40 => '#595454',
        Gray41 => '#5C5858',
        Gray42 => '#5F5A59',
        Gray43 => '#625D5D',
        Gray44 => '#646060',
        Gray45 => '#666362',
        Gray46 => '#696565',
        Gray47 => '#6D6968',
        Gray48 => '#6E6A6B',
        Gray49 => '#726E6D',
        Gray50 => '#747170',
        Green => '#00FF00',
        Green1 => '#5FFB17',
        Green2 => '#59E817',
        Green3 => '#4CC417',
        Green4 => '#347C17',
        GreenYellow => '#B1FB17',
        HotPink => '#F660AB',
        HotPink1 => '#F665AB',
        HotPink2 => '#E45E9D',
        HotPink3 => '#C25283',
        HotPink4 => '#7D2252',
        IndianRed1 => '#F75D59',
        IndianRed2 => '#E55451',
        IndianRed3 => '#C24641',
        IndianRed4 => '#7E2217',
        Khaki => '#ADA96E',
        Khaki1 => '#FFF380',
        Khaki2 => '#EDE275',
        Khaki3 => '#C9BE62',
        Khaki4 => '#827839',
        Lavendar => '#E3E4FA',
        LavendarBlush => '#FDEEF4',
        LavendarBlush2 => '#EBDDE2',
        LavendarBlush3 => '#C8BBBE',
        LavendarBlush4 => '#817679',
        LawnGreen => '#87F717',
        LemonChiffon => '#FFF8C6',
        LemonChiffon2 => '#ECE5B6',
        LemonChiffon3 => '#C9C299',
        LemonChiffon4 => '#827B60',
        LightBlue => '#ADDFFF',
        LightBlue1 => '#BDEDFF',
        LightBlue2 => '#AFDCEC',
        LightBlue3 => '#95B9C7',
        LightBlue4 => '#5E767E',
        LightCoral => '#E77471',
        LightCyan => '#E0FFFF',
        LightCyan2 => '#CFECEC',
        LightCyan3 => '#AFC7C7',
        LightCyan4 => '#717D7D',
        LightGolden2 => '#ECD672',
        LightGoldenrod => '#ECD872',
        LightGoldenrod1 => '#FFE87C',
        LightGoldenrod3 => '#C8B560',
        LightGoldenrod4 => '#817339',
        LightGoldenrodYellow => '#FAF8CC',
        LightPink => '#FAAFBA',
        LightPink1 => '#F9A7B0',
        LightPink2 => '#E799A3',
        LightPink3 => '#C48189',
        LightPink4 => '#7F4E52',
        LightSalmon => '#F9966B',
        LightSalmon2 => '#E78A61',
        LightSalmon3 => '#C47451',
        LightSalmon4 => '#7F462C',
        LightSeaGreen => '#3EA99F',
        LightSkyBlue => '#82CAFA',
        LightSkyBlue2 => '#A0CFEC',
        LightSkyBlue3 => '#87AFC7',
        LightSkyBlue4 => '#566D7E',
        LightSlateBlue => '#736AFF',
        LightSlateGray => '#6D7B8D',
        LightSteelBlue => '#728FCE',
        LightSteelBlue1 => '#C6DEFF',
        LightSteelBlue2 => '#B7CEEC',
        LightSteelBlue4 => '#646D7E',
        LimeGreen => '#41A317',
        Magenta => '#FF00FF',
        Magenta1 => '#F433FF',
        Magenta2 => '#E238EC',
        Magenta3 => '#C031C7',
        Maroon => '#810541',
        Maroon1 => '#F535AA',
        Maroon2 => '#E3319D',
        Maroon3 => '#C12283',
        Maroon4 => '#7D0552',
        MediumAquamarine => '#348781',
        MediumForestGreen => '#347235',
        MediumOrchid => '#B048B5',
        MediumOrchid1 => '#D462FF',
        MediumOrchid2 => '#C45AEC',
        MediumOrchid3 => '#A74AC7',
        MediumOrchid4 => '#6A287E',
        MediumPurple => '#8467D7',
        MediumPurple1 => '#9E7BFF',
        MediumPurple2 => '#9172EC',
        MediumPurple3 => '#7A5DC7',
        MediumPurple4 => '#4E387E',
        MediumSeaGreen => '#306754',
        MediumSlateBlue => '#5E5A80',
        MediumSpringGreen => '#348017',
        MediumTurquoise => '#48CCCD',
        MediumVioletRed => '#CA226B',
        MidnightBlue => '#151B54',
        PaleTurquoise3 => '#92C7C7',
        PaleTurquoise4 => '#5E7D7E',
        PaleVioletRed => '#D16587',
        PaleVioletRed1 => '#F778A1',
        PaleVioletRed2 => '#E56E94',
        PaleVioletRed3 => '#C25A7C',
        PaleVioletRed4 => '#7E354D',
        Pink => '#FAAFBE',
        Pink2 => '#E7A1B0',
        Pink3 => '#C48793',
        Pink4 => '#7F525D',
        Plum => '#B93B8F',
        Plum1 => '#F9B7FF',
        Plum2 => '#E6A9EC',
        Plum3 => '#C38EC7',
        Plum4 => '#7E587E',
        Purple => '#8E35EF',
        Purple1 => '#893BFF',
        Purple2 => '#7F38EC',
        Purple3 => '#6C2DC7',
        Purple4 => '#461B7E',
        Red => '#FF0000',
        Red1 => '#F62217',
        Red2 => '#E41B17',
        RosyBrown => '#B38481',
        RosyBrown1 => '#FBBBB9',
        RosyBrown2 => '#E8ADAA',
        RosyBrown3 => '#C5908E',
        RosyBrown4 => '#7F5A58',
        RoyalBlue => '#2B60DE',
        RoyalBlue1 => '#306EFF',
        RoyalBlue2 => '#2B65EC',
        RoyalBlue3 => '#2554C7',
        RoyalBlue4 => '#15317E',
        Salmon1 => '#F88158',
        Salmon2 => '#E67451',
        Salmon3 => '#C36241',
        Salmon4 => '#7E3817',
        SandyBrown => '#EE9A4D',
        SeaGreen => '#4E8975',
        SeaGreen1 => '#6AFB92',
        SeaGreen2 => '#64E986',
        SeaGreen3 => '#54C571',
        SeaGreen4 => '#387C44',
        Sienna => '#8A4117',
        Sienna1 => '#F87431',
        Sienna2 => '#E66C2C',
        Sienna3 => '#C35817',
        Sienna4 => '#7E3517',
        SkyBlue => '#6698FF',
        SkyBlue1 => '#82CAFF',
        SkyBlue2 => '#79BAEC',
        SkyBlue3 => '#659EC7',
        SkyBlue4 => '#41627E',
        SlateBlue => '#3574EC7',
        SlateBlue => '#737CA1',
        SlateBlue => '#737CA1',
        SlateBlue2 => '#6960EC',
        SlateBlue4 => '#342D7E',
        SlateGray => '#657383',
        SlateGray1 => '#C2DFFF',
        SlateGray2 => '#B4CFEC',
        SlateGray3 => '#98AFC7',
        SlateGray4 => '#616D7E',
        SpringGreen => '#4AA02C',
        SpringGreen => '#4AA02C',
        SpringGreen1 => '#5EFB6E',
        SpringGreen2 => '#57E964',
        SpringGreen3 => '#4CC552',
        SpringGreen4 => '#347C2C',
        SteelBlue => '#4863A0',
        SteelBlue1 => '#5CB3FF',
        SteelBlue2 => '#56A5EC',
        SteelBlue3 => '#488AC7',
        SteelBlue4 => '#2B547E',
        Thistle => '#D2B9D3',
        Thistle1 => '#FCDFFF',
        Thistle2 => '#E9CFEC',
        Thistle3 => '#C6AEC7',
        Thistle4 => '#806D7E',
        Turquoise => '#43C6DB',
        Turquoise1 => '#52F3FF',
        Turquoise2 => '#4EE2EC',
        Turquoise3 => '#43BFC7',
        White => '#FFFFFF',
        Violet => '#8D38C9',
        VioletRed => '#F6358A',
        VioletRed1 => '#F6358A',
        VioletRed2 => '#E4317F',
        VioletRed3 => '#C12869',
        VioletRed4 => '#7D0541',
        Yellow => '#FFFF00',
        Yellow1 => '#FFFC17',
        YellowGreen => '#52D017',
    );


my %name2rgb = map { $_ => [ map { hex( $_ ) / 255 }
                             $name2html{ $_ } =~ m/^#([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/
                           ]
                   }
               keys %name2html;

#  Convert html to RGB:

#  namedcolor
#  #xxxxxx
#  #xxx
#  xxxxxx
#  xxx

sub html2rgb {
    my $html = lc shift;     #  Lower case
    $html =~ s/\s+//g;       #  No spaces
    $html =~ s/grey/gray/g;  #  USA spelling

    my $rgb;
    if ( $rgb = $name2rgb{ $html } ) { return wantarray ? @$rgb : $rgb }

    my @rgb = map { hex( $_ ) / 255 }
              $html =~ m/^#([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/ ? ( $1, $2, $3 )
            : $html =~ m/^#([\da-f])([\da-f])([\da-f])/                      ? map { "$_$_" } ( $1, $2, $3 )
            : $html =~ m/^([\da-f][\da-f])([\da-f][\da-f])([\da-f][\da-f])/  ? ( $1, $2, $3 )
            : $html =~ m/^([\da-f])([\da-f])([\da-f])/                       ? map { "$_$_" } ( $1, $2, $3 )
            :                                                                 ( '7f', '7f', '7f' );

    wantarray() ? @rgb : \@rgb
}


#  Produce the gray equivalent in brightness to an RGB value:

sub rgb2gray {
    my ( $r, $g, $b ) = @_;
    if ( ref( $r ) eq "ARRAY" ) { ( $r, $g, $b ) = @$r }
    defined( $r ) && defined( $g ) && defined( $b ) || return undef;
    if ( $r > 1 ) { $r = 1 } elsif ( $r < 0 ) { $r = 0 }
    if ( $g > 1 ) { $g = 1 } elsif ( $g < 0 ) { $g = 0 }
    if ( $b > 1 ) { $b = 1 } elsif ( $b < 0 ) { $b = 0 }
    #  Various ITU recommendations and the new standard:
    # 0.299 * $r + 0.587 * $g + 0.114 * $b;  #  Rec 601-1
    # 0.213 * $r + 0.715 * $g + 0.072 * $b;  #  Rec 709
    0.222 * $r + 0.707 * $g + 0.071 * $b;  #  ITU std (D65 white point)
}


#  Convert an RGB value to an HTML string:

sub rgb2html {
    my ( $r, $g, $b ) = @_;
    if ( ref( $r ) eq "ARRAY" ) { ( $r, $g, $b ) = @$r }
    defined( $r ) && defined( $g ) && defined( $b ) || return undef;
    if ( $r > 1 ) { $r = 1 } elsif ( $r < 0 ) { $r = 0 }
    if ( $g > 1 ) { $g = 1 } elsif ( $g < 0 ) { $g = 0 }
    if ( $b > 1 ) { $b = 1 } elsif ( $b < 0 ) { $b = 0 }
    sprintf("#%02x%02x%02x", int(255.999*$r), int(255.999*$g), int(255.999*$b) )
}


#-------------------------------------------------------------------------------
#  Blend 2 or more RGB colors:
#
#     $color = blend_rgb_colors( $color1, $color2, ... )
#-------------------------------------------------------------------------------
sub blend_rgb_colors
{
    my @rgb = ( 0, 0, 0 );
    my $n = 0;
    while ( @_ )
    {
        my @clr = @{ shift @_ };
        @rgb = map { $_ + shift @clr } @rgb;
        $n++;
    }
    @rgb = map { $_/$n } @rgb if $n;
    wantarray() ? @rgb : \@rgb
}


#-------------------------------------------------------------------------------
#  Blend 2 or more HTML colors:
#
#     $color = blend_html_colors( $color1, $color2, ... )
#-------------------------------------------------------------------------------
sub blend_html_colors
{
    my @rgb = ( 0, 0, 0 );
    my $n = 0;
    while ( @_ )
    {
        my @clr = html2rgb( shift );
        @rgb = map { $_ + shift @clr } @rgb;
        $n++;
    }
    @rgb = map { $_/$n } @rgb if $n;

    rgb2html( @rgb );
}


#-------------------------------------------------------------------------------
#  Define a distance between 2 rgb colors
#
#    $name = rgb_distance( $rgb1, $rgb2 )
#-------------------------------------------------------------------------------
sub rgb_distance
{
    ( ref( $_[0] ) eq 'ARRAY' ) && ( ref( $_[0] ) eq 'ARRAY' ) || return undef;
    my @rgb1 = @{$_[0]};
    my @rgb2 = @{$_[1]};
    ( grep { defined } @rgb1, @rgb2 ) == 6 || return undef;
    my $d2 = ( $rgb1[0] - $rgb2[0] ) ** 2
           + ( $rgb1[1] - $rgb2[1] ) ** 2
           + ( $rgb1[2] - $rgb2[2] ) ** 2;
    return sqrt( $d2 );
}


#-------------------------------------------------------------------------------
#  Find the closest named color
#
#    $name = rgb2name( $rgb )
#-------------------------------------------------------------------------------
sub rgb2name
{
    my @rgb = ref( $_[0] ) eq 'ARRAY' ? @{ $_[0] } : @_;
    ( grep { defined } @rgb ) == 3 || return undef;

    my ( $name ) = map  { $_->[0] }
                   sort { $a->[1] <=> $b->[1] }
                   map  { [ $_, rgb_distance( \@rgb, $name2rgb{ $_ } ) ] }
                   keys %name2rgb;
    return $name;
}


1;

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3