183 lines
4 KiB
Perl
183 lines
4 KiB
Perl
#
|
|
# This code was forked from the LiveJournal project owned and operated
|
|
# by Live Journal, Inc. The code has been modified and expanded by
|
|
# Dreamwidth Studios, LLC. These files were originally licensed under
|
|
# the terms of the license supplied by Live Journal, Inc, which can
|
|
# currently be found at:
|
|
#
|
|
# http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt
|
|
#
|
|
# In accordance with the original license, this code and all its
|
|
# modifications are provided under the GNU General Public License.
|
|
# A copy of that license can be found in the LICENSE file included as
|
|
# part of this distribution.
|
|
#
|
|
|
|
package S2::Color;
|
|
use strict;
|
|
|
|
# This is a helper package, useful for creating color lightening/darkening
|
|
# functions in core layers.
|
|
#
|
|
|
|
# rgb to hsv
|
|
# r, g, b = [0, 255]
|
|
# h, s, v = [0, 1), [0, 1], [0, 1]
|
|
sub rgb_to_hsv {
|
|
my ( $r, $g, $b ) = map { $_ / 255 } @_;
|
|
my ( $h, $s, $v );
|
|
|
|
my ( $max, $min ) = ( $r, $r );
|
|
foreach ( $g, $b ) {
|
|
$max = $_ if $_ > $max;
|
|
$min = $_ if $_ < $min;
|
|
}
|
|
return ( 0, 0, 0 ) if $max == 0;
|
|
|
|
$v = $max;
|
|
|
|
my $delta = $max - $min;
|
|
|
|
$s = $delta / $max;
|
|
return ( 0, $s, $v ) unless $delta;
|
|
|
|
if ( $r == $max ) {
|
|
$h = ( $g - $b ) / $delta;
|
|
}
|
|
elsif ( $g == $max ) {
|
|
$h = 2 + ( $b - $r ) / $delta;
|
|
}
|
|
else {
|
|
$h = 4 + ( $r - $g ) / $delta;
|
|
}
|
|
|
|
$h = ( $h * 60 ) % 360 / 360;
|
|
|
|
return ( $h, $s, $v );
|
|
}
|
|
|
|
# hsv to rgb
|
|
# h, s, v = [0, 1), [0, 1], [0, 1]
|
|
# r, g, b = [0, 255], [0, 255], [0, 255]
|
|
sub hsv_to_rgb {
|
|
my ( $H, $S, $V ) = @_;
|
|
|
|
if ( $S == 0 ) {
|
|
$V *= 255;
|
|
return ( $V, $V, $V );
|
|
}
|
|
|
|
$H *= 6;
|
|
my $I = POSIX::floor($H);
|
|
|
|
my $F = $H - $I;
|
|
my $P = $V * ( 1 - $S );
|
|
my $Q = $V * ( 1 - $S * $F );
|
|
my $T = $V * ( 1 - $S * ( 1 - $F ) );
|
|
|
|
foreach ( $V, $T, $P, $Q ) {
|
|
$_ = int( $_ * 255 + 0.5 );
|
|
}
|
|
|
|
return ( $V, $T, $P ) if $I == 0;
|
|
return ( $Q, $V, $P ) if $I == 1;
|
|
return ( $P, $V, $T ) if $I == 2;
|
|
return ( $P, $Q, $V ) if $I == 3;
|
|
return ( $T, $P, $V ) if $I == 4;
|
|
|
|
return ( $V, $P, $Q );
|
|
}
|
|
|
|
# rgb to hsv
|
|
# r, g, b = [0, 255], [0, 255], [0, 255]
|
|
# returns: (h, s, l) = [0, 1), [0, 1], [0, 1]
|
|
sub rgb_to_hsl {
|
|
|
|
# convert rgb to 0-1
|
|
my ( $R, $G, $B ) = map { $_ / 255 } @_;
|
|
|
|
# get min/max of {r, g, b}
|
|
my ( $max, $min ) = ( $R, $R );
|
|
foreach ( $G, $B ) {
|
|
$max = $_ if $_ > $max;
|
|
$min = $_ if $_ < $min;
|
|
}
|
|
|
|
# is gray?
|
|
my $delta = $max - $min;
|
|
if ( $delta == 0 ) {
|
|
return ( 0, 0, $max );
|
|
}
|
|
|
|
my ( $H, $S );
|
|
my $L = ( $max + $min ) / 2;
|
|
|
|
if ( $L < 0.5 ) {
|
|
$S = $delta / ( $max + $min );
|
|
}
|
|
else {
|
|
$S = $delta / ( 2.0 - $max - $min );
|
|
}
|
|
|
|
if ( $R == $max ) {
|
|
$H = ( $G - $B ) / $delta;
|
|
}
|
|
elsif ( $G == $max ) {
|
|
$H = 2 + ( $B - $R ) / $delta;
|
|
}
|
|
elsif ( $B == $max ) {
|
|
$H = 4 + ( $R - $G ) / $delta;
|
|
}
|
|
|
|
$H *= 60;
|
|
$H += 360.0 if $H < 0.0;
|
|
$H -= 360.0 if $H >= 360.0;
|
|
$H /= 360.0;
|
|
|
|
return ( $H, $S, $L );
|
|
|
|
}
|
|
|
|
# h, s, l = [0,1), [0,1], [0,1]
|
|
# returns: rgb: [0,255], [0,255], [0,255]
|
|
sub hsl_to_rgb {
|
|
my ( $H, $S, $L ) = @_;
|
|
|
|
# gray.
|
|
if ( $S < 0.0000000000001 ) {
|
|
my $gv = int( 255 * $L + 0.5 );
|
|
return ( $gv, $gv, $gv );
|
|
}
|
|
|
|
my ( $t1, $t2 );
|
|
if ( $L < 0.5 ) {
|
|
$t2 = $L * ( 1.0 + $S );
|
|
}
|
|
else {
|
|
$t2 = $L + $S - $L * $S;
|
|
}
|
|
$t1 = 2.0 * $L - $t2;
|
|
|
|
my $fromhue = sub {
|
|
my $hue = shift;
|
|
if ( $hue < 0 ) { $hue += 1.0; }
|
|
if ( $hue > 1 ) { $hue -= 1.0; }
|
|
|
|
if ( 6.0 * $hue < 1 ) {
|
|
return $t1 + ( $t2 - $t1 ) * $hue * 6.0;
|
|
}
|
|
elsif ( 2.0 * $hue < 1 ) {
|
|
return $t2;
|
|
}
|
|
elsif ( 3.0 * $hue < 2.0 ) {
|
|
return ( $t1 + ( $t2 - $t1 ) * ( ( 2.0 / 3.0 ) - $hue ) * 6.0 );
|
|
}
|
|
else {
|
|
return $t1;
|
|
}
|
|
};
|
|
|
|
return map { int( 255 * $fromhue->($_) + 0.5 ) } ( $H + 1.0 / 3.0, $H, $H - 1.0 / 3.0 );
|
|
}
|
|
|
|
1;
|