# I do not do the linear approximation for $u/$un <= 0.008859 sub RGB2Lab { my ($red, $green, $blue) = @_; my ($x, $y, $z) = _RGB2XYZitu($red, $green, $blue); my ($xn, $yn, $zn) = _RGB2XYZitu(1,1,1); my $fx = _cuberoot($x/$xn); my $fy = _cuberoot($y/$yn); my $fz = _cuberoot($z/$zn); return ( 116*$fy-16, 500*($fx - $fy), 200*($fy - $fz) ); } sub Lab2RGB { my ($L, $a, $b) = @_; my ($xn, $yn, $zn) = _RGB2XYZitu(1,1,1); my $fL = _cube(($L+16)/116); my $fa = _cube($a/500); my $fb = _cube($b/200); my $y = _cube( ($L+16)/116) * $yn; my $x = _cube( ($L+16)/116 + $a/500 ) * $xn; my $z = _cube( ($L+16)/116 - $b/200 ) * $zn; return _XYZitu2RGB($x, $y, $z); } sub _RGB2XYZitu { my ($r, $g, $b) = @_; return ( 0.431*$r + 0.342*$g + 0.178*$b, 0.222*$r + 0.707*$g + 0.071*$b, 0.020*$r + 0.130*$g + 0.939*$b ); } sub _XYZitu2RGB { my ($x, $y, $z) = @_; return map { $_ > 1 ? 1 : $_ } ( 3.063*$x - 1.393*$y - 0.476*$z, -0.969*$x + 1.876*$y + 0.042*$z, 0.068*$x - 0.229*$y + 1.069*$z ); } sub _cuberoot { my $x = shift; return 0 if $x == 0; my $sign = ($x < 0) ? -1 : 1; $x *= $sign; return $sign * exp( log($x)/3.0 ); } sub _cube { my $x = shift; return 0 if $x == 0; my $sign = ($x < 0) ? -1 : 1; $x *= $sign; return $sign * exp( 3 * log($x) ); }