## HSV and RGB

HSV and RGB defines color spaces. HSV stands for Hue, Saturation, Value, while RGB stands for Red, Green, Blue. This page provides way(s) to convert values between these two color formats.

Googie 11.07.2007 - The code below uses only math package from tcllib, so it's fully portable. It implements routines described on Wikipedia .

KPV These routines appear in several other places in this wiki but it's good to have them in one place (see Harmonic color wheel, Selecting visually different RGB colors, and Image Processing with HSV).

I added hls2rgb from one of the above pages, and I removed the math package requirement (it only used functions min and max, now in 8.5).

Note the rgbToHsv / hsvToRgb pair encodes saturation and value from 0-255, not the usual 0-100%. Edit the code below, replace 255 with 100 to make them work in the normal ranges PS 24.2.2020.

``` proc rgbToHsv {r g b} {
set temp  [expr {min(\$r, \$g, \$b)}]
set value [expr {max(\$r, \$g, \$b)}]
set range [expr {\$value-\$temp}]
if {\$range == 0} {
set hue 0
} else {
if {\$value == \$r} {
set top [expr {\$g-\$b}]
if {\$g >= \$b} {
set angle 0
} else {
set angle 360
}
} elseif {\$value == \$g} {
set top [expr {\$b-\$r}]
set angle 120
} elseif {\$value == \$b} {
set top [expr {\$r-\$g}]
set angle 240
}
set hue [expr { round( double(\$top) / \$range * 60 + \$angle ) }]
}

if {\$value == 0} {
set saturation 0
} else {
set saturation [expr { round( 255 - double(\$temp) / \$value * 255 ) }]
}
return [list \$hue \$saturation \$value]
}

proc hsvToRgb {h s v} {
set Hi [expr { int( double(\$h) / 60 ) % 6 }]
set f [expr { double(\$h) / 60 - \$Hi }]
set s [expr { double(\$s)/255 }]
set v [expr { double(\$v)/255 }]
set p [expr { double(\$v) * (1 - \$s) }]
set q [expr { double(\$v) * (1 - \$f * \$s) }]
set t [expr { double(\$v) * (1 - (1 - \$f) * \$s) }]
switch -- \$Hi {
0 {
set r \$v
set g \$t
set b \$p
}
1 {
set r \$q
set g \$v
set b \$p
}
2 {
set r \$p
set g \$v
set b \$t
}
3 {
set r \$p
set g \$q
set b \$v
}
4 {
set r \$t
set g \$p
set b \$v
}
5 {
set r \$v
set g \$p
set b \$q
}
default {
error "Wrong Hi value in hsvToRgb procedure! This should never happen!"
}
}
set r [expr {round(\$r*255)}]
set g [expr {round(\$g*255)}]
set b [expr {round(\$b*255)}]
return [list \$r \$g \$b]
}

proc hls2rgb {h l s} {
# h, l and s are floats between 0.0 and 1.0, ditto for r, g and b
# h = 0   => red
# h = 1/3 => green
# h = 2/3 => blue

set h6 [expr {(\$h-floor(\$h)) * 6}]
set r [expr {(\$h6 <= 3) ? (2-\$h6) : (\$h6-4)}]
set g [expr {(\$h6 <= 2) ? (\$h6) :
(\$h6 <= 5) ? (4-\$h6) : (\$h6-6)}]
set b [expr {(\$h6 <= 1) ? (-\$h6) :
(\$h6 <= 4) ? (\$h6-2) : (6-\$h6)}]
set r [expr {max(0.0, min(1.0, double(\$r)))}]
set g [expr {max(0.0, min(1.0, double(\$g)))}]
set b [expr {max(0.0, min(1.0, double(\$b)))}]

set r [expr {((\$r-1) * \$s + 1) * \$l}]
set g [expr {((\$g-1) * \$s + 1) * \$l}]
set b [expr {((\$b-1) * \$s + 1) * \$l}]
return [list \$r \$g \$b]
}

# Demo
set r 100
set g 200
set b 150
foreach {h s v} [rgbToHsv \$r \$g \$b] {}
puts "rgb: \$r \$g \$b -> hsv: \$h \$s \$v"
puts "back to hsv: [hsvToRgb \$h \$s \$v]"```