package Colour; # Colour conversion to/from RGB/HSV use strict; =head1 NAME Colour - Colour conversion RGB <=> HSV =head1 SYNOPSIS use Colour; my @rgb = (255,153,102); # Pale Brown @rgb = map {$_ /= 255 } @rgb; # Convert to values from 0 to 1 print "HSV values: ", (join ",", RGBtoHSV(@rgb)), "\n"; my @hsv = (20, 0.6, 1); # Pale Brown print "RGB values: ", (join ",", HSVtoRGB(@hsv)), "\n"; =head1 DESCRIPTION The purpose of this module is to easily convert between RGB and HSV (or HSB) values. The main interest in doing so is that the HSV system is more user-friendly than the RGB. The Hue is the 'tone' of the color. It's the most awkward parameter to set since you're not supposed to know that values around 240 are for blues or values around 60 are for yellows. A 'circle of color' is not very hard to find though... The Saturation value is the 'amount' of color you want, ranging from white (no color) to the full color. The Value (or Brightness) is the 'lightness' of the color. A low value makes the color black whereas high value makes the color brighter. This module is stolen from http://www.cs.rit.edu/~ncs/color/t_convert.html thanks to [merlyn] and [Rudif] for pointing me to the URL. =cut use v5.6.0; # not too hard to tweak otherwise :) require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(RGBtoHSV HSVtoRGB); our $VERSION = 0.1; #use POSIX; =head1 DESCRIPTION =head2 RGBtoHSV($r, $g, $b) The three RGB values ranges from 0 to 1. The function returns a three element array with the HSV values in it. =cut sub RGBtoHSV { my ($r, $g, $b) = @_; my ($h, $s, $v); my ($min, $max, $delta); ($min, undef, $max) = sort ($r, $g, $b); $v = $max; $delta = $max - $min; if( $max != 0 ){ $s = $delta / $max; } else { # $r = $g = $b = 0 # $s = 0, $v is undef $s = 0; $h = -1; return ($h, $s, $v); } if( $r == $max ){ $h = ( $g - $b ) / $delta; # between yellow & magenta } elsif( $g == $max ){ $h = 2 + ( $b - $r ) / $delta; # between cyan & yellow } else { $h = 4 + ( $r - $g ) / $delta; # between magenta & cyan } $h *= 60; # degrees if( $h < 0 ){ $h += 360; } return ($h, $s, $v); } =head2 HSVtoRGB ($h, $s, $v) The $h (hue) is in degrees, ranging from 0 to 360. The two other values, $s (saturation) and $v (value, brightness) are ranging from 0 to 1. If the saturation is set to 0, the colour resulting will be in grayscale (each RGB value being the same). =cut sub HSVtoRGB { my ($h, $s, $v) = @_; my ($r, $g, $b); my($i, $f, $p, $q, $t); if( $s == 0 ) { # achromatic (grey) $r = $g = $b = $v; return ($r, $g, $b); } $h /= 60; # sector 0 to 5 #$i = floor( $h ); $i = $h =~ /^(\d+)\./; # substitute for POSIX::floor function? $f = $h - $i; # factorial part of h $p = $v * ( 1 - $s ); $q = $v * ( 1 - $s * $f ); $t = $v * ( 1 - $s * ( 1 - $f ) ); if ($i == 0){ ($r, $g, $b) = ($v, $t, $p)} elsif ($i == 1){ ($r, $g, $b) = ($q, $v, $p)} elsif ($i == 2){ ($r, $g, $b) = ($p, $v, $t)} elsif ($i == 3){ ($r, $g, $b) = ($p, $q, $v)} elsif ($i == 4){ ($r, $g, $b) = ($t, $p, $v)} else { ($r, $g, $b) = ($v, $p, $q)} # if 5 } =head1 EXPORTS Both functions are exported. =cut "She comes in color everywhere";