#!/usr/bin/perl # # This is a helper package, useful for creating color lightening/darkening # functions in core layers. # package S2::Color; # 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;