PHP snippet: RGB ↔ HSV colour conversion
A small PHP class for converting colours between RGB and HSV, handy for twisting pictures and generating captchas.
- Originally
- 2007
- Reviewed
- 2026-11
- Revision
- 2
HSV (hue, saturation, value) is a much friendlier space than RGB when you want to shift a colour: rotate the hue, wash out the saturation, darken the value, then convert back. I used this class for picture twisting and for generating captchas with GD.
Usage
$c = new ColorMangler();
[$c->r, $c->g, $c->b] = [133, 64, 127]; // heather, #85407F
$c->toHSV();
$c->h = fmod($c->h + 0.5, 1); // rotate the hue half a turn
$c->authorative = 'hsv'; // h/s/v now hold the truth
echo $c->toHEX(); // the complementary green
$colour = $c->getTrueColor($im); // or allocate it in a GD imageThe class
// HSV values: 0-1. RGB values: 0-255.
class ColorMangler
{
public string $authorative = 'rgb'; // set to 'hsv' after changing h/s/v, so the outputs convert first
public float $r = 0, $g = 0, $b = 0, $h = 0, $s = 0, $v = 0;
public function toHSV(): void
{
$var_R = $this->r / 255;
$var_G = $this->g / 255;
$var_B = $this->b / 255;
$var_Min = min($var_R, $var_G, $var_B);
$var_Max = max($var_R, $var_G, $var_B);
$del_Max = $var_Max - $var_Min;
$V = $var_Max;
if ($del_Max == 0) {
$H = 0;
$S = 0;
} else {
$S = $del_Max / $var_Max;
$del_R = ((($var_Max - $var_R) / 6) + ($del_Max / 2)) / $del_Max;
$del_G = ((($var_Max - $var_G) / 6) + ($del_Max / 2)) / $del_Max;
$del_B = ((($var_Max - $var_B) / 6) + ($del_Max / 2)) / $del_Max;
if ($var_R == $var_Max) {
$H = $del_B - $del_G;
} elseif ($var_G == $var_Max) {
$H = (1 / 3) + $del_R - $del_B;
} else {
$H = (2 / 3) + $del_G - $del_R;
}
if ($H < 0) {
$H++;
}
if ($H > 1) {
$H--;
}
}
$this->h = $H;
$this->s = $S;
$this->v = $V;
}
public function toRGB(): void
{
$H = $this->h;
$S = $this->s;
$V = $this->v;
if ($S == 0) {
$R = $G = $B = $V * 255;
} else {
$var_H = $H == 1 ? 0 : $H * 6; // H = 1 is the same hue as 0
$var_i = floor($var_H);
$var_1 = $V * (1 - $S);
$var_2 = $V * (1 - $S * ($var_H - $var_i));
$var_3 = $V * (1 - $S * (1 - ($var_H - $var_i)));
if ($var_i == 0) {
[$var_R, $var_G, $var_B] = [$V, $var_3, $var_1];
} elseif ($var_i == 1) {
[$var_R, $var_G, $var_B] = [$var_2, $V, $var_1];
} elseif ($var_i == 2) {
[$var_R, $var_G, $var_B] = [$var_1, $V, $var_3];
} elseif ($var_i == 3) {
[$var_R, $var_G, $var_B] = [$var_1, $var_2, $V];
} elseif ($var_i == 4) {
[$var_R, $var_G, $var_B] = [$var_3, $var_1, $V];
} else {
[$var_R, $var_G, $var_B] = [$V, $var_1, $var_2];
}
$R = $var_R * 255;
$G = $var_G * 255;
$B = $var_B * 255;
}
// Whole numbers: GD and %02X take ints, and PHP 8.1+ warns on lossy float-to-int conversion.
$this->r = round($R);
$this->g = round($G);
$this->b = round($B);
}
public function toHEX(): string
{
if ($this->authorative == 'hsv') {
$this->toRGB();
}
return sprintf('#%02X%02X%02X', $this->r, $this->g, $this->b);
}
public function toCSSRGB(): string
{
if ($this->authorative == 'hsv') {
$this->toRGB();
}
return 'rgb(' . $this->r . ',' . $this->g . ',' . $this->b . ')';
}
public function getTrueColor(GdImage $im): int|false
{
if ($this->authorative == 'hsv') {
$this->toRGB();
}
return imagecolorallocate($im, (int)$this->r, (int)$this->g, (int)$this->b);
}
}Where this came from. Written for the old ljunggren.net code-snippets page. The conversion follows the widely used EasyRGB RGB/HSV formulas.