Par programme Éclaircir ou assombrir une couleur hexadécimale (ou rvb, et mélanger les couleurs)


Voici une fonction sur laquelle je travaillais pour éclaircir ou assombrir par programme une couleur hexadécimale d'une quantité spécifique. Il suffit de passer une chaîne comme "3F6D2A" pour la couleur (col) et un entier base10 (amt) pour la quantité à éclaircir ou à assombrir. Pour assombrir, passez un nombre négatif (c'est-à-dire -20).

La raison pour laquelle j'ai fait cela était à cause de toutes les solutions que j'ai trouvées, jusqu'à présent, elles semblaient trop compliquer la question. Et j'avais le sentiment que cela pourrait être fait avec seulement quelques lignes de code. S'il vous plaît laissez-moi savoir si vous trouvez des problèmes, ou avoir des ajustements à faire qui permettrait d'accélérer.

function LightenDarkenColor(col,amt) {
    col = parseInt(col,16);
    return (((col & 0x0000FF) + amt) | ((((col>> 8) & 0x00FF) + amt) << 8) | (((col >> 16) + amt) << 16)).toString(16);
}

Pour le développement, voici une version plus facile à lire:

function LightenDarkenColor(col,amt) {
    var num = parseInt(col,16);
    var r = (num >> 16) + amt;
    var b = ((num >> 8) & 0x00FF) + amt;
    var g = (num & 0x0000FF) + amt;
    var newColor = g | (b << 8) | (r << 16);
    return newColor.toString(16);
}

Et enfin une version pour gérer les couleurs qui peuvent (ou non) avoir le "#" au début. Plus réglage pour les valeurs de couleur incorrectes:

function LightenDarkenColor(col,amt) {
    var usePound = false;
    if ( col[0] == "#" ) {
        col = col.slice(1);
        usePound = true;
    }

    var num = parseInt(col,16);

    var r = (num >> 16) + amt;

    if ( r > 255 ) r = 255;
    else if  (r < 0) r = 0;

    var b = ((num >> 8) & 0x00FF) + amt;

    if ( b > 255 ) b = 255;
    else if  (b < 0) b = 0;

    var g = (num & 0x0000FF) + amt;

    if ( g > 255 ) g = 255;
    else if  ( g < 0 ) g = 0;

    return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
}

OK, alors maintenant ce n'est pas seulement quelques lignes, mais cela semble beaucoup plus simple et si vous n'utilisez pas le " # " et n'avez pas besoin de vérifier les couleurs hors de portée, c'est seulement un couple de lignes.

Si vous n'utilisez pas le "#", vous pouvez simplement l'ajouter dans le code comme:

var myColor = "3F6D2A";
myColor = LightenDarkenColor(myColor,10);
thePlaceTheColorIsUsed = ("#" + myColor);

Je suppose que ma question principale est, suis-je correct ici? Cela ne couvre - t-il pas certaines situations (normales)?

Author: Pimp Trizkit, 2011-04-06

11 answers

TL; DR? --Vous voulez simplement éclaircir / assombrir (ombrage)? Passez à la version 2, choisissez celle pour RGB ou Hex. -- Vous voulez un shader/blender/converter complet avec errorcheck et alpha et 3 chiffres hex? Utilisez la version 3 près du bas.

Vous pouvez utiliser la version 3.1: jsfiddle > Exemple shadeBlendConvert

Version 3.1 sur GitHub: Goto GitHub > PJs > cssp


Après quelques réflexions... J'ai décidé de répondre à ma propre question. An et demi plus tard. Ce fut vraiment une aventure avec des idées de plusieurs utilisateurs utiles, et je vous remercie tous! Celui-ci est pour l'équipe! Bien que ce ne soit pas nécessairement la réponse que je cherchais. Parce que si ce que dit James Khoury est vrai, alors il n'y a pas de vrai calcul hexadécimal en javascript, je dois utiliser des décimales, cette double conversion est nécessaire. Si nous faisons cette hypothèse, alors c'est probablement le moyen le plus rapide que j'ai vu (ou vous pensez) pour alléger (ajouter le blanc) ou assombrir (ajouter noir) arbitraire Couleur RBG par pourcentage. Il tient également compte des problèmes d'acide frais mentionnés sur sa réponse à cette question (il pads 0s). Mais cette version appelle toString une seule fois. Cela tient également compte des limites hors plage (il appliquera 0 et 255 comme limites).

Mais attention, l'entrée de couleur doit être EXACTEMENT 7 caractères, comme #08a35c. (ou 6 si vous utilisez la version supérieure)

Merci à Pablo pour l'inspiration et l'idée d'utiliser percentage. Pour cela, je garderai le nom de la fonction le même! Mdr! Cependant, celui-ci est différent, car il normalise le pourcentage à 255 et ajoute ainsi la même quantité à chaque couleur (plus de blanc). Si vous passez en 100 pour percent cela rendra votre couleur blanc pur. Si vous passez 0 pour percent, rien ne se passera. Si vous passez 1 pour percent, il ajoutera 3 nuances à toutes les couleurs (2,55 nuances pour 1%, arrondies). Donc, vous passez vraiment dans un pourcentage de blanc (ou noir, utilisez négatif). Par conséquent, cette version vous permet d'alléger le rouge pur (FF0000), par exemple.

Je également utilisé un aperçu de la réponse de Keith Mashinter à cette question: Comment convertir décimal en hexadécimal en JavaScript?

J'ai supprimé certaines parenthèses apparemment inutiles. (comme dans l'instruction double ternaire et dans crafting G) Je ne sais pas si cela va jouer avec la priorité de l'opérateur dans certains environnements. Testé bien dans FireFox.

function shadeColor1(color, percent) {  // deprecated. See below.
    var num = parseInt(color,16),
    amt = Math.round(2.55 * percent),
    R = (num >> 16) + amt,
    G = (num >> 8 & 0x00FF) + amt,
    B = (num & 0x0000FF) + amt;
    return (0x1000000 + (R<255?R<1?0:R:255)*0x10000 + (G<255?G<1?0:G:255)*0x100 + (B<255?B<1?0:B:255)).toString(16).slice(1);
}

Ou, si vous voulez qu'il gère le"#":

function shadeColor1(color, percent) {  // deprecated. See below.
    var num = parseInt(color.slice(1),16), amt = Math.round(2.55 * percent), R = (num >> 16) + amt, G = (num >> 8 & 0x00FF) + amt, B = (num & 0x0000FF) + amt;
    return "#" + (0x1000000 + (R<255?R<1?0:R:255)*0x10000 + (G<255?G<1?0:G:255)*0x100 + (B<255?B<1?0:B:255)).toString(16).slice(1);
}

Comment ça pour deux lignes de code?

EDIT: Corrigé BG swap gaffe. Merci svachalek!


UPDATE MISE À JOUR-Version 2 avec mélange {

Un peu plus d'un an plus tard, encore, et c'est toujours en cours. Mais cette fois, je pense que c'est fait. Notant les problèmes mentionnés sur le fait de ne pas utiliser HSL pour éclaircir correctement la couleur. Il existe une technique qui élimine la plupart de cette inexactitude sans avoir à convertir en HSL. Le principal problème est qu'un canal de couleur sera complètement saturé avant le reste de la couleur. Provoquant un changement de teinte après ce point. Je trouvé à ces questions ici, ici et ici, qui m'a mis sur la bonne voie. Marquer Rançon du post - m'a montré la différence, et Keith post m'a montré le chemin. Lerp est le sauveur. C'est la même chose que le mélange de couleurs, j'ai donc également créé une fonction blendColors.


TL; DR - Pour éclaircir/assombrir simplement, utilisez cette fonction shadeColor2 ci-dessous. Ou son homologue RVB shadeRGBColor plus bas, et donnez-moi une voix. Mais, si vous vous voulez tout et/ou tous les goodies. Tels que la possibilité d'utiliser à la fois les couleurs RVB et hexadécimales, la vérification des erreurs, le décodage hexadécimal à 3 chiffres, le mélange, les canaux Alpha et les conversions RGB2Hex / Hex2RGB. Ensuite, passez à la version 3 pour shadeBlendConvert pour obtenir toutes les cloches et de sifflets et me donner deux votes. Vous pouvez ensuite supprimer quelques lignes pour supprimer certaines de ces fonctionnalités, si vous le souhaitez. Et vous obtenez un vote si vous vous souvenez que la Version 1 shadeColor1 ci-dessus est obsolète pour toutes les utilisations.


Donc, sans plus tarder:

-La Version 2 Hex-

function shadeColor2(color, percent) {   
    var f=parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF;
    return "#"+(0x1000000+(Math.round((t-R)*p)+R)*0x10000+(Math.round((t-G)*p)+G)*0x100+(Math.round((t-B)*p)+B)).toString(16).slice(1);
}

function blendColors(c0, c1, p) {
    var f=parseInt(c0.slice(1),16),t=parseInt(c1.slice(1),16),R1=f>>16,G1=f>>8&0x00FF,B1=f&0x0000FF,R2=t>>16,G2=t>>8&0x00FF,B2=t&0x0000FF;
    return "#"+(0x1000000+(Math.round((R2-R1)*p)+R1)*0x10000+(Math.round((G2-G1)*p)+G1)*0x100+(Math.round((B2-B1)*p)+B1)).toString(16).slice(1);
}

Plus loin:

Il n'y a pas de vérification d'erreur, donc les valeurs qui sont passées dans lesquelles sont hors plage provoqueront des résultats inattendus. De plus, l'entrée de couleur doit être EXACTEMENT 7 caractères, comme #08a35c. Mais tous les autres goodies sont toujours là comme le plafonnement de la plage de sortie (sorties 00-FF), le rembourrage (0A), les poignées # et utilisables sur des couleurs solides, comme #FF0000.

Cette nouvelle version de shadeColor prend en flotteur pour sa deuxième paramètre. Pour shadeColor2, la plage valide pour le deuxième paramètre (pourcentage) est de -1.0 à 1.0.

Et pour blendColors la plage valide pour le troisième paramètre (pourcentage) est 0.0 à 1.0, les négatifs ne sont pas autorisés ici.

Cette nouvelle version ne prend plus un pourcentage de blanc pur, comme l'ancienne version. Il prend un pourcentage de la DISTANCE de la couleur donnée au blanc pur. Dans l'ancienne version, il était facile de saturer la couleur, et comme un résultat, beaucoup de couleurs seraient calculées en blanc pur lors de l'utilisation d'un pourcentage important. Cette nouvelle façon, il ne calcule en blanc pur que si vous passez 1.0, ou en noir pur, utilisez -1.0.

Appeler blendColors(color, "#FFFFFF", 0.5) est la même chose que shadeColor2(color,0.5). Ainsi que, blendColors(color,"#000000", 0.5) est le même que shadeColor2(color,-0.5). Juste un peu plus lent.

shadeColor2 est plus lent que shadeColor1, mais pas par une notable quantité. (Attendez, c'est une déclaration qui se contredit!)

La précision acquise peut être vue ici:

-- Version 2 RVB RGB

function shadeRGBColor(color, percent) {
    var f=color.split(","),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=parseInt(f[0].slice(4)),G=parseInt(f[1]),B=parseInt(f[2]);
    return "rgb("+(Math.round((t-R)*p)+R)+","+(Math.round((t-G)*p)+G)+","+(Math.round((t-B)*p)+B)+")";
}

function blendRGBColors(c0, c1, p) {
    var f=c0.split(","),t=c1.split(","),R=parseInt(f[0].slice(4)),G=parseInt(f[1]),B=parseInt(f[2]);
    return "rgb("+(Math.round((parseInt(t[0].slice(4))-R)*p)+R)+","+(Math.round((parseInt(t[1])-G)*p)+G)+","+(Math.round((parseInt(t[2])-B)*p)+B)+")";
}

Utilisations:

var color1 = "rbg(63,131,163)";
var lighterColor = shadeRGBColor(color1, 0.5);  //  rgb(159,193,209)
var darkerColor = shadeRGBColor(color1, -0.25); //  rgb(47,98,122)

var color2 = "rbg(244,128,0)";
var blend1 = blendRGBColors(color1, color2, 0.75);  //  rgb(199,129,41)
var blend2 = blendRGBColors(color2, color1, 0.62);  //  rgb(132,130,101)

-- Version 2 Universel A {

function shade(color, percent){
    if (color.length > 7 ) return shadeRGBColor(color,percent);
    else return shadeColor2(color,percent);
}

function blend(color1, color2, percent){
    if (color1.length > 7) return blendRGBColors(color1,color2,percent);
    else return blendColors(color1,color2,percent);
}

Utilisation:

var color1 = shade("rbg(63,131,163)", 0.5);
var color2 = shade("#3f83a3", 0.5);
var color3 = blend("rbg(63,131,163)", "rbg(244,128,0)", 0.5);
var color4 = blend("#3f83a3", "#f48000", 0.5);

-- La Version 2 Universel B --

Ok, très bien! La popularité de cette réponse m'a fait penser que je pourrais faire une bien meilleure version universelle de cela. Si vous pouvez y aller! Cette version est une fonction tout-en-un copy/paste-able shader/blender pour les couleurs RVB et hexadécimales. Celui ci n'est pas vraiment différent de l'autre version Uni fourni ci-dessus. Sauf que c'est beaucoup plus petit et juste une fonction à coller et à utiliser. Je pense que la taille est passée d'environ 1 592 caractères à 557 caractères, si vous le compressez en une seule ligne. Bien sûr, si vous n'avez pas besoin de l'utiliser de manière interchangeable entre RGB et Hex, alors vous n'avez pas besoin d'une version universelle comme celle-ci de toute façon, lol. Il suffit d'utiliser l'une des versions beaucoup plus petites et plus rapides ci-dessus; approprié pour votre schéma de couleurs. Aller de l'avant... À certains égards, c'est un peu plus rapide, dans certains comment son un peu plus lent. Je n'ai fait aucune analyse de test de vitesse finale. Il y a deux différences d'utilisation: Premièrement, le pourcentage est maintenant le premier paramètre de la fonction, au lieu du dernier. Deuxièmement, lors du mélange, vous pouvez utiliser des nombres négatifs. Ils seront juste convertis en nombres positifs.

Plus de bruit:

function shadeBlend(p,c0,c1) {
    var n=p<0?p*-1:p,u=Math.round,w=parseInt;
    if(c0.length>7){
        var f=c0.split(","),t=(c1?c1:p<0?"rgb(0,0,0)":"rgb(255,255,255)").split(","),R=w(f[0].slice(4)),G=w(f[1]),B=w(f[2]);
        return "rgb("+(u((w(t[0].slice(4))-R)*n)+R)+","+(u((w(t[1])-G)*n)+G)+","+(u((w(t[2])-B)*n)+B)+")"
    }else{
        var f=w(c0.slice(1),16),t=w((c1?c1:p<0?"#000000":"#FFFFFF").slice(1),16),R1=f>>16,G1=f>>8&0x00FF,B1=f&0x0000FF;
        return "#"+(0x1000000+(u(((t>>16)-R1)*n)+R1)*0x10000+(u(((t>>8&0x00FF)-G1)*n)+G1)*0x100+(u(((t&0x0000FF)-B1)*n)+B1)).toString(16).slice(1)
    }
}

Utilisation:

var color1 = "#FF343B";
var color2 = "#343BFF";
var color3 = "rgb(234,47,120)";
var color4 = "rgb(120,99,248)";
var shadedcolor1 = shadeBlend(0.75,color1);
var shadedcolor3 = shadeBlend(-0.5,color3);
var blendedcolor1 = shadeBlend(0.333,color1,color2);
var blendedcolor34 = shadeBlend(-0.8,color3,color4); // Same as using 0.8

Maintenant il pourrait être parfait! ;) @ Mevin

* V2 AUTRES LANGUES *

-- L'extension Swift-RGB (par Matej Ukmar) --

extension UIColor {
    func shadeColor(factor: CGFloat) -> UIColor {
        var r: CGFloat = 0
        var g: CGFloat = 0
        var b: CGFloat = 0
        var a: CGFloat = 0
        var t: CGFloat = factor < 0 ? 0 : 1
        var p: CGFloat = factor < 0 ? -factor : factor
        getRed(&r, green: &g, blue: &b, alpha: &a)
        r = (t-r)*p+r
        g = (t-g)*p+g
        b = (t-b)*p+b
        return UIColor(red: r, green: g, blue: b, alpha: a)
    }
}

-- la Version de PHP - HEX (par Kevin M) --

function shadeColor2($color, $percent) {
    $color = str_replace("#", "", $color);
    $t=$percent<0?0:255;
    $p=$percent<0?$percent*-1:$percent;
    $RGB = str_split($color, 2);
    $R=hexdec($RGB[0]);
    $G=hexdec($RGB[1]);
    $B=hexdec($RGB[2]);
    return '#'.substr(dechex(0x1000000+(round(($t-$R)*$p)+$R)*0x10000+(round(($t-$G)*$p)+$G‌​)*0x100+(round(($t-$B)*$p)+$B)),1);
}


UPDATE MISE À JOUR Version Version 3.1 Universelle {

(Cela a été ajoutée à ma bibliothèque à GitHub)

Dans quelques mois, cela fera encore un an depuis la dernière version universelle. Si... merci àsricks commentaire perspicace. J'ai décidé de le prendre à la niveau suivant, de nouveau. Ce n'est plus le démon de la vitesse à deux lignes comme il avait commencé, lol. Mais, pour ce qu'il fait, il est assez rapide et petit. C'est environ 1600 octets. Si vous supprimez ErrorChecking et supprimez le décodage à 3 chiffres, vous pouvez le réduire à environ 1200 octets et c'est plus rapide. C'est beaucoup de pouvoir sur un K. imaginez, vous pouvez charger ce sur un Commodore64 et encore de l'espace pour 50 de plus! (Sans tenir compte du fait que le moteur JavaScript est plus grand que 63k)

Apparemment il y avait plus à faire:

const shadeBlendConvert = function (p, from, to) {
    if(typeof(p)!="number"||p<-1||p>1||typeof(from)!="string"||(from[0]!='r'&&from[0]!='#')||(to&&typeof(to)!="string"))return null; //ErrorCheck
    if(!this.sbcRip)this.sbcRip=(d)=>{
        let l=d.length,RGB={};
        if(l>9){
            d=d.split(",");
            if(d.length<3||d.length>4)return null;//ErrorCheck
            RGB[0]=i(d[0].split("(")[1]),RGB[1]=i(d[1]),RGB[2]=i(d[2]),RGB[3]=d[3]?parseFloat(d[3]):-1;
        }else{
            if(l==8||l==6||l<4)return null; //ErrorCheck
            if(l<6)d="#"+d[1]+d[1]+d[2]+d[2]+d[3]+d[3]+(l>4?d[4]+""+d[4]:""); //3 or 4 digit
            d=i(d.slice(1),16),RGB[0]=d>>16&255,RGB[1]=d>>8&255,RGB[2]=d&255,RGB[3]=-1;
            if(l==9||l==5)RGB[3]=r((RGB[2]/255)*10000)/10000,RGB[2]=RGB[1],RGB[1]=RGB[0],RGB[0]=d>>24&255;
        }
    return RGB;}
    var i=parseInt,r=Math.round,h=from.length>9,h=typeof(to)=="string"?to.length>9?true:to=="c"?!h:false:h,b=p<0,p=b?p*-1:p,to=to&&to!="c"?to:b?"#000000":"#FFFFFF",f=this.sbcRip(from),t=this.sbcRip(to);
    if(!f||!t)return null; //ErrorCheck
    if(h)return "rgb"+(f[3]>-1||t[3]>-1?"a(":"(")+r((t[0]-f[0])*p+f[0])+","+r((t[1]-f[1])*p+f[1])+","+r((t[2]-f[2])*p+f[2])+(f[3]<0&&t[3]<0?")":","+(f[3]>-1&&t[3]>-1?r(((t[3]-f[3])*p+f[3])*10000)/10000:t[3]<0?f[3]:t[3])+")");
    else return "#"+(0x100000000+r((t[0]-f[0])*p+f[0])*0x1000000+r((t[1]-f[1])*p+f[1])*0x10000+r((t[2]-f[2])*p+f[2])*0x100+(f[3]>-1&&t[3]>-1?r(((t[3]-f[3])*p+f[3])*255):t[3]>-1?r(t[3]*255):f[3]>-1?r(f[3]*255):255)).toString(16).slice(1,f[3]>-1||t[3]>-1?undefined:-2);
}
Vous pouvez utiliser la version 3.1: jsfiddle > Exemple shadeBlendConvert

Le calcul de base de cette version est le même que précédemment. Mais, j'ai fait un refactoring majeur. Cela a permis une fonctionnalité et un contrôle beaucoup plus importants. Il convertit maintenant intrinsèquement RGB2Hex et Hex2RGB.

Toutes les anciennes fonctionnalités de la v2 ci-dessus devraient toujours être ici. J'ai essayé de tout tester, veuillez poster un commentaire si vous trouvez quelque chose de mal. De toute façon, voici les nouvelles fonctionnalités:

  • Accepte les codes couleur hexadécimaux à 3 chiffres (ou 4 chiffres), sous la forme #RGB (ou #ARGB). Il va développer. Supprimez la ligne marquée par //3 digit pour supprimer cette fonctionnalité.
  • Accepte et mélange les canaux alpha. Si la couleur from ou la couleur to a un canal alpha, alors le résultat aura un canal alpha. Si les deux couleurs ont un canal alpha, le résultat sera un mélange des deux canaux alpha, en utilisant le pourcentage donné (comme s'il s'agissait d'un canal de couleur normal). Si une seule des deux couleurs a un canal alpha, cet alpha sera simplement transmis au résultat. Cela permet de mélanger / ombrer une couleur transparente tout en maintenant le niveau de transparence. Ou, si le niveau transparent doit également se fondre, assurez-vous que les deux couleurs ont des alphas. L'ombrage passera à travers le canal alpha, si vous voulez un ombrage de base qui mélange également le canal alpha, utilisez rgb(0,0,0,1) ou rgb(255,255,255,1) comme couleur to (ou leur hexadécimal équivalent). Pour les couleurs RVB, le canal alpha résultant sera arrondi à 4 décimales.
  • Les conversions RGB2Hex et Hex2RGB sont maintenant implicites lors de l'utilisation du mélange. La couleur du résultat sera toujours sous la forme de la couleur to, si elle existe. S'il n'y a pas de couleur to, passez 'c' en tant que couleur to et elle ombrera et convertira. Si la conversion n'est souhaitée que, passez également 0 comme pourcentage.
  • Une fonction secondaire est ajoutée au global as Bien. sbcRip peut être passé une couleur hex ou rbg et il renvoie un objet contenant ces informations de couleur. Son sous la forme: {0:R,1:G,2:B,3:A}. Où R G de et B avons la gamme 0 à 255. Et quand il n'y a pas d'alpha: A est -1. Sinon: Un a une plage 0.0000 à 1.0000.
  • Une vérification d'erreur mineure a été ajoutée. Il n'est pas parfait. Il peut encore l'écrasement. Mais ça va attraper des trucs. Fondamentalement, si la structure est fausse à certains égards ou si le le pourcentage n'est pas un nombre ou hors de portée, il retournera null. Un exemple: shadeBlendConvert(0.5,"salt") = null , où, comme il pense #salt est valide couleur. Supprimez les quatre lignes marquées par //ErrorCheck pour supprimer cette fonctionnalité.

Utilisations:

let color1 = "rgb(20,60,200)";
let color2 = "rgba(20,60,200,0.67423)";
let color3 = "#67DAF0";
let color4 = "#5567DAF0";
let color5 = "#F3A";
let color6 = "#F3A9";
let color7 = "rgb(200,60,20)";
let color8 = "rgba(200,60,20,0.98631)";
let c;

// Shade (Lighten or Darken)
c = shadeBlendConvert ( 0.42, color1 ); // rgb(20,60,200) + [42% Lighter] => rgb(119,142,223)
c = shadeBlendConvert ( -0.4, color5 ); // #F3A + [40% Darker] => #991f66
c = shadeBlendConvert ( 0.42, color8 ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(223,142,119,0.98631)
// Shade with Conversion (use "c" as your "to" color)
c = shadeBlendConvert ( 0.42, color2, "c" ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #778edfac
// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
c = shadeBlendConvert ( 0, color6, "c" ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)
// Blending
c = shadeBlendConvert ( -0.5, color2, color8 ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(110,60,110,0.8303)
c = shadeBlendConvert ( 0.7, color2, color7 ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(146,60,74,0.67423)
c = shadeBlendConvert ( 0.25, color3, color7 ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(127,179,185)
c = shadeBlendConvert ( 0.75, color7, color3 ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #7fb3b9
// Error Checking
c = shadeBlendConvert ( 0.42, "#FFBAA" ); // #FFBAA + [42% Lighter] => null  (Invalid Input Color)
c = shadeBlendConvert ( 42, color1, color5 ); // rgb(20,60,200) + #F3A + [4200% Blend] => null  (Invalid Percentage Range)
c = shadeBlendConvert ( 0.42, {} ); // [object Object] + [42% Lighter] => null  (Strings Only for Color)
c = shadeBlendConvert ( "42", color1 ); // rgb(20,60,200) + ["42"] => null  (Numbers Only for Percentage)
c = shadeBlendConvert ( 0.42, "salt" ); // salt + [42% Lighter] => null  (A Little Salt is No Good...)
// Error Check Fails (Some Errors are not Caught)
c = shadeBlendConvert ( 0.42, "#salt" ); // #salt + [42% Lighter] => #6b6b6b00  (...and a Pound of Salt is Jibberish)
// Ripping
c = sbcRip ( color4 ); // #5567DAF0 + [Rip] => [object Object] => {'0':85,'1':103,'2':218,'3':0.9412}

J'hésite maintenant à appeler cela fait... Encore une fois...

PT

EDIT EDIT: A commuté la version 3 pour utiliser let, et une fonction de flèche, et a ajouté this aux appels sbcRip.

----======----

J'ai tellement honte! (et surpris que personne ne l'ait mentionné) Apparemment, je n'utilise pas de canaux alpha dans mes propres projets... ET... apparemment, j'ai fait des tests terribles. La version 3 ne lisait ni n'écrivait correctement les couleurs avec les canaux alpha. Il y avait quelques points que j'avais juste mal ou jamais réellement appris:

  • Les couleurs hexadécimales avec alpha sont #RGBA (pas #ARGB). La version 3 lisait et écrivait cela à l'envers.
  • Couleurs RVB avec alphasdoit être rgba() et non rgb(); la version 3 ne sort jamais rgba().
  • La version 3 n'a pas accepté rgba() mais a accepté les alphas dans rgb(), ce qui ne devrait pas arriver.

Je tout à l'heure a remplacé la version 3 par la version 3.1 où ces problèmes sont résolus. Je ne l'ai pas posté comme une fonction distincte ici; vu que l'ancienne version 3 devrait être retirée de l'existence et remplacée par celle-ci. Et c'est ce que j'ai fait. La version 3 ci dessus est en fait la version 3.1.

Toutes les anciennes fonctionnalités d'en haut sont toujours là avec ces mises à jour:

  • Lit et écrit correctement les couleurs avec les canaux alpha. Les deux Hex et RGB.
  • La couleur to accepte maintenant une couleur de chaîne ou un falsy (qui peut toujours être undefined).
  • La fonction est maintenant constante.

... Je suis content d'avoir hésité à le répéter. Nous voici, une autre année ou deux plus tard ... encore le perfectionner...

PT

 772
Author: Pimp Trizkit, 2018-03-10 07:44:10

J'ai fait une solution qui fonctionne très bien pour moi:

function shadeColor(color, percent) {

    var R = parseInt(color.substring(1,3),16);
    var G = parseInt(color.substring(3,5),16);
    var B = parseInt(color.substring(5,7),16);

    R = parseInt(R * (100 + percent) / 100);
    G = parseInt(G * (100 + percent) / 100);
    B = parseInt(B * (100 + percent) / 100);

    R = (R<255)?R:255;  
    G = (G<255)?G:255;  
    B = (B<255)?B:255;  

    var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
    var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
    var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));

    return "#"+RR+GG+BB;
}

Exemple Alléger:

shadeColor("#63C6FF",40);

Exemple Assombrir:

shadeColor("#63C6FF",-40);
 70
Author: Pablo, 2013-07-30 16:02:21

J'ai essayé votre fonction et il y avait un petit bogue: Si une valeur 'r' finale n'est que de 1 chiffre, le résultat apparaît comme: 'a0a0a' lorsque la bonne valeur est '0a0a0a', par exemple. Je viens de le réparer rapidement en ajoutant ceci au lieu de votre retour:

var rStr = (r.toString(16).length < 2)?'0'+r.toString(16):r.toString(16);
var gStr = (g.toString(16).length < 2)?'0'+g.toString(16):g.toString(16);
var bStr = (b.toString(16).length < 2)?'0'+b.toString(16):b.toString(16);

return (usePound?"#":"") + rStr + gStr + bStr;

Peut-être que ce n'est pas si agréable mais ça fait le travail. Grande fonction, BTW. Juste ce dont j'avais besoin. :)

 4
Author: Cool Acid, 2012-01-06 20:13:50

Avez-vous pensé à une conversion rvb > hsl? ensuite, déplacez simplement la luminosité de haut en bas? c'est la façon dont je voudrais aller.

Un rapide coup d'oeil pour quelques algorithmes m'a obtenu les sites suivants.

PHP: http://serennu.com/colour/rgbtohsl.php

JavaScript: http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript

EDIT le lien ci-dessus n'est plus valide. Vous pouvez afficher git hub pour la source de la page ou gist

Alternativement, une autre question StackOverflow pourrait être un bon endroit pour regarder.


Même si ce n'est pas le bon choix pour l'OP, ce qui suit est une approximation du code que je suggérais à l'origine. (En supposant que vous avez des fonctions de conversion rvb/hsl)

var SHADE_SHIFT_AMOUNT = 0.1; 

function lightenShade(colorValue)
{
    if(colorValue && colorValue.length >= 6)
    {
        var redValue = parseInt(colorValue.slice(-6,-4), 16);
        var greenValue = parseInt(colorValue.slice(-4,-2), 16);
        var blueValue = parseInt(colorValue.slice(-2), 16);

        var hsl = rgbToHsl(redValue, greenValue, blueValue);
        hsl[2]= Math.min(hsl[2] + SHADE_SHIFT_AMOUNT, 1);
        var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
        return "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
    }
    return null;
}

function darkenShade(colorValue)
{
    if(colorValue && colorValue.length >= 6)
    {
        var redValue = parseInt(colorValue.slice(-6,-4), 16);
        var greenValue = parseInt(colorValue.slice(-4,-2), 16);
        var blueValue = parseInt(colorValue.slice(-2), 16);

        var hsl = rgbToHsl(redValue, greenValue, blueValue);
        hsl[2]= Math.max(hsl[2] - SHADE_SHIFT_AMOUNT, 0);
        var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
        return "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
    }
    return null;
}

Cela suppose:

  1. Vous avez les fonctions hslToRgb et rgbToHsl.
  2. Le paramètre colorValue est une chaîne sous la forme #RRVVBB

Bien que si nous discutons de css, il existe une syntaxe pour spécifier hsl/hsla pour IE9/Chrome/Firefox.

 3
Author: James Khoury, 2017-05-23 12:26:36

C'est ce que j'ai utilisé en fonction de votre fonction. Je préfère utiliser les étapes plutôt que le pourcentage car c'est plus intuitif pour moi.

Par exemple, 20% d'une valeur bleue 200 est très différent de 20% d'une valeur bleue 40.

Quoi qu'il en soit, voici ma modification, merci pour votre fonction d'origine.

function adjustBrightness(col, amt) {

    var usePound = false;

    if (col[0] == "#") {
        col = col.slice(1);
        usePound = true;
    }

    var R = parseInt(col.substring(0,2),16);
    var G = parseInt(col.substring(2,4),16);
    var B = parseInt(col.substring(4,6),16);

    // to make the colour less bright than the input
    // change the following three "+" symbols to "-"
    R = R + amt;
    G = G + amt;
    B = B + amt;

    if (R > 255) R = 255;
    else if (R < 0) R = 0;

    if (G > 255) G = 255;
    else if (G < 0) G = 0;

    if (B > 255) B = 255;
    else if (B < 0) B = 0;

    var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
    var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
    var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));

    return (usePound?"#":"") + RR + GG + BB;

}
 3
Author: Eric Sloan, 2018-07-16 04:06:26

La méthode suivante vous permettra d'éclaircir ou d'assombrir la valeur d'exposition d'une chaîne de couleur hexadécimale (hexadécimale):

private static string GetHexFromRGB(byte r, byte g, byte b, double exposure)
{
    exposure = Math.Max(Math.Min(exposure, 1.0), -1.0);
    if (exposure >= 0)
    {
        return "#"
            + ((byte)(r + ((byte.MaxValue - r) * exposure))).ToString("X2")
            + ((byte)(g + ((byte.MaxValue - g) * exposure))).ToString("X2")
            + ((byte)(b + ((byte.MaxValue - b) * exposure))).ToString("X2");
    }
    else
    {
        return "#"
            + ((byte)(r + (r * exposure))).ToString("X2")
            + ((byte)(g + (g * exposure))).ToString("X2")
            + ((byte)(b + (b * exposure))).ToString("X2");
    }

}

Pour la dernière valeur de paramètre dans GetHexFromRGB(), Passez une valeur double quelque part entre -1 et 1 (-1 est noir, 0 est inchangé, 1 est blanc):

// split color (#e04006) into three strings
var r = Convert.ToByte("e0", 16);
var g = Convert.ToByte("40", 16);
var b = Convert.ToByte("06", 16);

GetHexFromRGB(r, g, b, 0.25);  // Lighten by 25%;
 2
Author: Jason Williams, 2017-12-07 22:36:26

Je voulais changer une couleur en un niveau de luminositéspécifique à - quelle que soit la luminosité de la couleur avant-voici une simple fonction JS qui semble bien fonctionner, bien que je sois sûr qu'elle pourrait être plus courte

function setLightPercentage(col: any, p: number) {
    const R = parseInt(col.substring(1, 3), 16);
    const G = parseInt(col.substring(3, 5), 16);
    const B = parseInt(col.substring(5, 7), 16);
    const curr_total_dark = (255 * 3) - (R + G + B);

    // calculate how much of the current darkness comes from the different channels
    const RR = ((255 - R) / curr_total_dark);
    const GR = ((255 - G) / curr_total_dark);
    const BR = ((255 - B) / curr_total_dark);

    // calculate how much darkness there should be in the new color
    const new_total_dark = ((255 - 255 * (p / 100)) * 3);

    // make the new channels contain the same % of available dark as the old ones did
    const NR = 255 - Math.round(RR * new_total_dark);
    const NG = 255 - Math.round(GR * new_total_dark);
    const NB = 255 - Math.round(BR * new_total_dark);

    const RO = ((NR.toString(16).length === 1) ? "0" + NR.toString(16) : NR.toString(16));
    const GO = ((NG.toString(16).length === 1) ? "0" + NG.toString(16) : NG.toString(16));
    const BO = ((NB.toString(16).length === 1) ? "0" + NB.toString(16) : NB.toString(16));

    return "#" + RO + GO + BO;}
 2
Author: Torbjörn Josefsson, 2018-03-07 10:37:42

Version C#... notez que j'obtiens des chaînes de couleur dans ce format # FF12AE34, et j'ai besoin de découper le #FF.

    private string GetSmartShadeColorByBase(string s, float percent)
    {
        if (string.IsNullOrEmpty(s))
            return "";
        var r = s.Substring(3, 2);
        int rInt = int.Parse(r, NumberStyles.HexNumber);
        var g = s.Substring(5, 2);
        int gInt = int.Parse(g, NumberStyles.HexNumber);
        var b = s.Substring(7, 2);
        int bInt = int.Parse(b, NumberStyles.HexNumber);

        var t = percent < 0 ? 0 : 255;
        var p = percent < 0 ? percent*-1 : percent;

        int newR = Convert.ToInt32(Math.Round((t - rInt) * p) + rInt);
        var newG = Convert.ToInt32(Math.Round((t - gInt) * p) + gInt);
        var newB = Convert.ToInt32(Math.Round((t - bInt) * p) + bInt);

        return String.Format("#{0:X2}{1:X2}{2:X2}", newR, newG, newB);
    }
 1
Author: user1618171, 2014-09-23 20:14:19

Comment simplifier la couleur de l'ombre en PHP?

<?php
function shadeColor ($color='#cccccc', $percent=-25) {

  $color = Str_Replace("#",Null,$color);

  $r = Hexdec(Substr($color,0,2));
  $g = Hexdec(Substr($color,2,2));
  $b = Hexdec(Substr($color,4,2));

  $r = (Int)($r*(100+$percent)/100);
  $g = (Int)($g*(100+$percent)/100);
  $b = (Int)($b*(100+$percent)/100);

  $r = Trim(Dechex(($r<255)?$r:255));  
  $g = Trim(Dechex(($g<255)?$g:255));  
  $b = Trim(Dechex(($b<255)?$b:255));

  $r = ((Strlen($r)==1)?"0{$r}":$r);
  $g = ((Strlen($g)==1)?"0{$g}":$g);
  $b = ((Strlen($b)==1)?"0{$b}":$b);

  return (String)("#{$r}{$g}{$b}");
}

echo shadeColor(); // #999999
 0
Author: jsebestyan, 2015-05-17 19:15:50

J'ai fait un portage de l'excellente bibliothèque xcolor pour supprimer sa dépendance jQuery. Il y a une tonne de fonctions là-dedans, y compris les couleurs éclaircissantes et assombrissantes.

Vraiment, la conversion hex en RVB est une fonction complètement distincte de l'éclaircissement ou de l'assombrissement des couleurs. Gardez les choses au SEC s'il vous plait. Dans tous les cas, une fois que vous avez une couleur RVB, vous pouvez simplement ajouter la différence entre le niveau de lumière que vous voulez et le niveau de lumière que vous avez à chacune des valeurs RVB:

var lightness = function(level) {
    if(level === undefined) {
        return Math.max(this.g,this.r,this.b)
    } else {
        var roundedLevel = Math.round(level) // fractions won't work here
        var levelChange = roundedLevel - this.lightness()

        var r = Math.max(0,this.r+levelChange)
        var g = Math.max(0,this.g+levelChange)
        var b = Math.max(0,this.b+levelChange)

        if(r > 0xff) r = 0xff
        if(g > 0xff) g = 0xff
        if(b > 0xff) b = 0xff

        return xolor({r: r, g: g, b: b})
    }
}

var lighter = function(amount) {
    return this.lightness(this.lightness()+amount)
}

Voir https://github.com/fresheneesz/xolor pour plus de la source.

 0
Author: B T, 2017-01-17 02:52:06

Je voulais depuis longtemps pouvoir produire des teintes / nuances de couleurs, voici ma solution JavaScript:

const varyHue = function (hueIn, pcIn) {
    const truncate = function (valIn) {
        if (valIn > 255) {
            valIn = 255;
        } else if (valIn < 0)  {
            valIn = 0;
        }
        return valIn;
    };

    let red   = parseInt(hueIn.substring(0, 2), 16);
    let green = parseInt(hueIn.substring(2, 4), 16);
    let blue  = parseInt(hueIn.substring(4, 6), 16);
    let pc    = parseInt(pcIn, 10);    //shade positive, tint negative
    let max   = 0;
    let dif   = 0;

    max = red;

    if (pc < 0) {    //tint: make lighter
        if (green < max) {
            max = green;
        }

        if (blue < max) {
            max = blue;
        }

        dif = parseInt(((Math.abs(pc) / 100) * (255 - max)), 10);

        return leftPad(((truncate(red + dif)).toString(16)), '0', 2)  + leftPad(((truncate(green + dif)).toString(16)), '0', 2) + leftPad(((truncate(blue + dif)).toString(16)), '0', 2);
    } else {    //shade: make darker
        if (green > max) {
            max = green;
        }

        if (blue > max) {
            max = blue;
        }

        dif = parseInt(((pc / 100) * max), 10);

        return leftPad(((truncate(red - dif)).toString(16)), '0', 2)  + leftPad(((truncate(green - dif)).toString(16)), '0', 2) + leftPad(((truncate(blue - dif)).toString(16)), '0', 2);
    }
};
 0
Author: user2655360, 2017-08-29 03:00:36