Javascript convertir HSB / HSV color en RVB avec précision

je dois convertir HSB avec précision en RVB, mais je ne suis pas sûr de savoir comment contourner le problème de transformer des décimales en nombres entiers sans arrondir. C'est la fonction courante que j'ai sortie d'une bibliothèque colorpicker:

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) };

comme vous pouvez le voir l'inexactitude dans cette fonction vient des mathématiques.rond

29
demandé sur Gigantic 2013-06-21 22:36:47

5 réponses

à Partir de Parthik Gosar 's lien dans ce commentaire avec de légères modifications pour vous permettre de saisir chaque valeur de façon indépendante ou tous à la fois comme un objet

/* accepts parameters
 * h  Object = {h:x, s:y, v:z}
 * OR 
 * h, s, v
*/
function HSVtoRGB(h, s, v) {
    var r, g, b, i, f, p, q, t;
    if (arguments.length === 1) {
        s = h.s, v = h.v, h = h.h;
    }
    i = Math.floor(h * 6);
    f = h * 6 - i;
    p = v * (1 - s);
    q = v * (1 - f * s);
    t = v * (1 - (1 - f) * s);
    switch (i % 6) {
        case 0: r = v, g = t, b = p; break;
        case 1: r = q, g = v, b = p; break;
        case 2: r = p, g = v, b = t; break;
        case 3: r = p, g = q, b = v; break;
        case 4: r = t, g = p, b = v; break;
        case 5: r = v, g = p, b = q; break;
    }
    return {
        r: Math.round(r * 255),
        g: Math.round(g * 255),
        b: Math.round(b * 255)
    };
}

ce code s'attend à 0 <= h, s, v <= 1 , si vous utilisez des degrés ou des radians, n'oubliez pas de les diviser.

les valeurs retournées 0 <= r, g, b <= 255 sont arrondies au nombre entier le plus proche 1519230920". Si vous ne voulez pas ce comportement, supprimez le Math.round de l'objet retourné.


Et l'inverse (avec moins de division)

/* accepts parameters
 * r  Object = {r:x, g:y, b:z}
 * OR 
 * r, g, b
*/
function RGBtoHSV(r, g, b) {
    if (arguments.length === 1) {
        g = r.g, b = r.b, r = r.r;
    }
    var max = Math.max(r, g, b), min = Math.min(r, g, b),
        d = max - min,
        h,
        s = (max === 0 ? 0 : d / max),
        v = max / 255;

    switch (max) {
        case min: h = 0; break;
        case r: h = (g - b) + d * (g < b ? 6: 0); h /= 6 * d; break;
        case g: h = (b - r) + d * 2; h /= 6 * d; break;
        case b: h = (r - g) + d * 4; h /= 6 * d; break;
    }

    return {
        h: h,
        s: s,
        v: v
    };
}

ce code va sortir 0 <= h, s, v <= 1 , mais ce temps prend n'importe quel 0 <= r, g, b <= 255 (n'a pas besoin d'être un entier)


Par souci d'exhaustivité,

function HSVtoHSL(h, s, v) {
    if (arguments.length === 1) {
        s = h.s, v = h.v, h = h.h;
    }
    var _h = h,
        _s = s * v,
        _l = (2 - s) * v;
    _s /= (_l <= 1) ? _l : 2 - _l;
    _l /= 2;

    return {
        h: _h,
        s: _s,
        l: _l
    };
}

function HSLtoHSV(h, s, l) {
    if (arguments.length === 1) {
        s = h.s, l = h.l, h = h.h;
    }
    var _h = h,
        _s,
        _v;

    l *= 2;
    s *= (l <= 1) ? l : 2 - l;
    _v = (l + s) / 2;
    _s = (2 * s) / (l + s);

    return {
        h: _h,
        s: _s,
        v: _v
    };
}

Toutes ces valeurs doivent être dans la gamme 0 à 1 . Pour HSL<->RGB passer par VHS .

71
répondu Paul S. 2017-06-13 23:49:41

étant donné la popularité croissante de npm je pense qu'il est intéressant de mentionner un paquet contenant toutes ces fonctions à travers une API simple:

npm install colorsys

var colorsys = require('colorsys')
colorsys.rgb_to_hsv({ r: 255, g: 255, b: 255 })
// { h: 0 , s: 0 , v: 100 }

pour le navigateur: <script src="http://netbeast.github.io/colorsys/browser.js"></script>

colorsys.rgb_to_hex(h, s, v)
// #hexcolor
5
répondu jsdario 2016-02-12 12:46:10

j'ai écrit une fois cette fonction:

function mix(a, b, v)
{
    return (1-v)*a + v*b;
}

function HSVtoRGB(H, S, V)
{
    var V2 = V * (1 - S);
    var r  = ((H>=0 && H<=60) || (H>=300 && H<=360)) ? V : ((H>=120 && H<=240) ? V2 : ((H>=60 && H<=120) ? mix(V,V2,(H-60)/60) : ((H>=240 && H<=300) ? mix(V2,V,(H-240)/60) : 0)));
    var g  = (H>=60 && H<=180) ? V : ((H>=240 && H<=360) ? V2 : ((H>=0 && H<=60) ? mix(V2,V,H/60) : ((H>=180 && H<=240) ? mix(V,V2,(H-180)/60) : 0)));
    var b  = (H>=0 && H<=120) ? V2 : ((H>=180 && H<=300) ? V : ((H>=120 && H<=180) ? mix(V2,V,(H-120)/60) : ((H>=300 && H<=360) ? mix(V,V2,(H-300)/60) : 0)));

    return {
        r : Math.round(r * 255),
        g : Math.round(g * 255),
        b : Math.round(b * 255)
    };
}

il attend 0<=h<=360, 0<=S<=1 et 0<=V<=1 et renvoie un objet qui contient R, G et B (valeurs entières entre 0 et 255). J'ai utilisé cette image pour créer le code.

3
répondu sigalor 2015-07-18 11:34:37

il y a un bug dans la fonction HSVtoHSL de Paul S: lorsque l'entrée v est 0, nous avons un problème de division par zéro et la sortie s devient NaN. Voici une correction:

function HSVtoHSL(h, s, v) {
    if (arguments.length === 1) {
        s = h.s, v = h.v, h = h.h;
    }
    var _h = h,
        _s = s * v,
        _l = (2 - s) * v;
    _s /= (_l <= 1) ? (_l === 0 ? 1 : _l) : 2 - _l;
    _l /= 2;

    return {
        h: _h,
        s: _s,
        l: _l;
    };
}

P.S. j'aurais ajouté ceci comme commentaire sur le post de Paul S., Mais je suis nouveau et le système m'a dit que je n'avais pas assez de rép.

0
répondu benlambert 2016-09-15 12:46:02

Voici l'algorithme en unityscript, vous devrez réécrire le flotteur, mathf.étage fonctions et la sortie est un vector3 de 3 flotteurs.

EDIT ceci était la première réponse sur cette page et il a semblé intéressant de fournir cette aide beaucoup quand il n'y avait pas d'autres réponses, avec la petite réserve que vous avez pour le convertir en une version presque identique dans JS.

function HSVToRGB(h : float, s : float, v : float) {
    h=h%1;
    s=s%1;
    v=v%1;

    var r : float;
    var g : float;
    var b : float;
    var i : float;
    var f : float;
    var p : float;
    var q : float;
    var t : float; 

    i = Mathf.Floor(h * 6);
    f = h * 6 - i;
    p = v * (1 - s);
    q = v * (1 - f * s);
    t = v * (1 - (1 - f) * s);

    switch (i % 6) {
        case 0: r = v; g = t; b = p; break;
        case 1: r = q; g = v; b = p; break;
        case 2: r = p; g = v; b = t; break;
        case 3: r = p; g = q; b = v; break;
        case 4: r = t; g = p; b = v; break;
        case 5: r = v; g = p; b = q; break;
    }
    return Color(r,g,b); 
}
-3
répondu com.prehensible 2016-04-17 15:35:37