I need to accurately convert HSB to RGB but I am not sure how to get around the problem of turning decimals into whole numbers without rounding. This is the current function I have out of a colorpicker library:
HSBToRGB = function (hsb) {
var rgb = { };
var h = Math.round(hsb.h);
var s = Math.round(hsb.s * 255 / 100);
var v = Math.round(hsb.b * 255 / 100);
if (s == 0) {
rgb.r = rgb.g = rgb.b = v;
} else {
var t1 = v;
var t2 = (255 - s) * v / 255;
var t3 = (t1 - t2) * (h % 60) / 60;
if (h == 360) h = 0;
if (h < 60) { rgb.r = t1; rgb.b = t2; rgb.g = t2 + t3 }
else if (h < 120) { rgb.g = t1; rgb.b = t2; rgb.r = t1 - t3 }
else if (h < 180) { rgb.g = t1; rgb.r = t2; rgb.b = t2 + t3 }
else if (h < 240) { rgb.b = t1; rgb.r = t2; rgb.g = t1 - t3 }
else if (h < 300) { rgb.b = t1; rgb.g = t2; rgb.r = t2 + t3 }
else if (h < 360) { rgb.r = t1; rgb.g = t2; rgb.b = t1 - t3 }
else { rgb.r = 0; rgb.g = 0; rgb.b = 0 }
}
return { r: Math.round(rgb.r), g: Math.round(rgb.g), b: Math.round(rgb.b) };
As you can see the inaccuracy in this function comes from the Math.round
Here is the algorithm in unityscript, you'll have to rewrite the float, mathf.floor functions and the output is a vector3 of 3 floats.
EDIT This was the first answer on this page and it seemed worthwile to provide this much help when there weren't any other answers, with the small reservation that you have to convert it to a nearly identical version in JS.
Given the rising popularity of npm I think it is worth to mention a package containing all this functions through a simple API:
npm install colorsys
For the browser:
<script src="http://netbeast.github.io/colorsys/browser.js"></script>
From Parthik Gosar's link in this comment with slight modification to let you enter each value independently or all at once as an object
This code expects
0 <= h, s, v <= 1
, if you're using degrees or radians, remember to divide them out.The returned
0 <= r, g, b <= 255
are rounded to the nearest Integer. If you don't want this behaviour remove theMath.round
s from the returned object.And the reverse (with less division)
This code will output
0 <= h, s, v <= 1
, but this time takes any0 <= r, g, b <= 255
(does not need to be an integer)For completeness,
All of these values should be in the range
0
to1
. ForHSL<->RGB
go via HSV.There's a bug in Paul S's
HSVtoHSL
function: when thev
input is 0 we get a divide-by-zero problem and thes
output becomes NaN. Here's a fix:P.S. I would have added this as a comment on Paul S.'s post, but I'm new and the system told me I don't have enough rep.
I once wrote this function:
It expects 0<=H<=360, 0<=S<=1 and 0<=V<=1 and returns an object that contains R, G and B (integer values between 0 and 255). I used this image to create the code.