Éclairer ou obscurcir programmatiquement une couleur hexadécimale( ou RVB, et les couleurs de mélange)

Voici une fonction sur laquelle je travaillais pour éclairer ou obscurcir programmatiquement une couleur hexadécimale d'une quantité spécifique. Il suffit de passer dans une chaîne de caractères comme "3F6D2A" pour la couleur ( col ) et un entier base10 ( amt ) pour la quantité à éclaircir ou assombrir. Pour assombrir, passer dans un nombre négatif (i.e. -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 compliquer la question. Et j'avais le sentiment que ça pourrait être fait avec juste 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);
}

For Development use 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 ne peuvent pas) avoir le " # " au début. Plus Ajustement pour des valeurs de couleur inappropriées:

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, donc maintenant ce n'est pas juste 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, ce n'est que quelques lignes.

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

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

je suppose que ma question principale est, Suis-je correct ici? Ne s'agit-il pas de situations (normales)?

393
demandé sur Pimp Trizkit 2011-04-06 04:39:35

11 réponses

TL;DR? -- voulez-vous un éclairage simple / assombri (ombrage)? Passez à la Version 2, choisissez celle pour RGB ou Hex. -- Vous voulez un shader/blender/converter complet avec errorcheck et alpha et hex à 3 chiffres? Utilisez la Version 3 près du fond.

Jouer avec la version 3.1: jsfiddle > shadeBlendConvert Exemple

Version 3.1 at GitHub: Goto Github > PJs > pSBC


après quelques réflexions... J'ai décidé de répondre à ma propre question. Un an et demi plus tard. Ce fut vraiment une aventure avec des idées de plusieurs utilisateurs serviables, 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 hex math en javascript, je dois utiliser des décimales, cette double conversion est nécessaire. Si nous faisons cette hypothèse, alors c'est probablement la façon la plus rapide que j'ai vu (ou peut penser) pour éclairer (ajouter le blanc) ou assombrir (ajouter le noir) une couleur RBG arbitraire par pourcentage. Il explique également les questions acide frais mentionnés sur sa réponse à cette question (il pads 0s). Mais cette version appelle toString une seule fois. Cela tient aussi pour hors de portée (il va appliquer 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 le pourcentage. Pour cela, je vais garder le nom de la fonction de même! lol! 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 il rendra votre couleur blanc pur. Si vous passez à 0 pour percent , il ne se passera rien. Si vous passez à 1 pour percent il ajoutera 3 teintes pour toutes les couleurs (2,55 teintes pour 1%, arrondi). Donc votre vraiment passer dans un pourcentage de blanc (ou noir, utilisez négatif). Par conséquent, cette version vous permet d'alléger rouge pur (FF0000), par exemple.

j'ai aussi utilisé insight de la réponse de Keith Mashinter à cette question: comment convertir décimal en hex en JavaScript?

j'ai supprimé quelques parenthèses apparemment inutiles. (comme dans la double déclaration ternaire et dans crafting G) Je ne sais pas si cela va affecter la priorité de l'opérateur dans certains environnements. Testé bon 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 le souhaitez gérer 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é B<->G swap gaffe. Merci svachalek!


-- mise à jour-Version 2 avec mélange --

Un peu plus d'un an plus tard, à nouveau, et son toujours en cours. Mais cette fois je pense que sa fait. Notant les problèmes mentionnés sur le fait de ne pas utiliser HSL pour éclairer correctement la couleur. Il y a une technique qui élimine la plupart de cette inexactitude sans avoir à convertir en HSL. Le problème principal 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. J'ai trouvé ces questions ici , ici et ici qui m'a mis sur la bonne voie. Marque 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 des couleurs, donc j'ai créé une fonction blendColors aussi.


TL; DR - pour alléger/assombrir simple utiliser cette fonction shadeColor2 ci-dessous. Ou son homologue du RVB shadeRGBColor plus bas, et donnez-moi une voix. Mais, si vous voulez tout et/ou tous les goodies. Comme la possibilité d'utiliser les couleurs RGB et Hex, la vérification des erreurs, le décodage hex à 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 sifflets et me donner deux votes. Vous pouvez ensuite supprimer quelques lignes à supprimer certains de ces éléments, si désiré. Et vous obtenez un vote si vous vous souvenez que La Version 1 shadeColor1 ci-dessus est dépréciée pour tous les usages.


Alors, sans plus tarder:

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

suite ado:

il n'y a pas de vérification d'erreur, de sorte que les valeurs qui sont passées en dehors de la plage causeront 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 encore ici comme le capsulage de gamme de sortie (sorties 00-FF), le rembourrage (0A), les poignées # , et utilisable sur des couleurs solides, comme #FF0000 .

cette nouvelle version de shadeColor prend un float pour son second paramètre. Pour shadeColor2 , la plage valide pour le second paramètre (pourcentage) est -1.0 à 1.0 .

et pour blendColors la fourchette valide pour le troisième (pourcentage) le paramètre est 0.0 à 1.0 , négatifs, pas autorisés ici.

cette nouvelle version ne prend plus un pourcentage de blanc pur, comme l'ancienne version. C'est prendre 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 en conséquence, de nombreuses couleurs computerait au blanc pur en utilisant un pourcentage appréciable. Cette nouvelle façon, il ne calcule blanc pur si vous passez dans 1.0 , ou noir pur, utilisez -1.0 .

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

shadeColor2 est plus lent que shadeColor1 , mais pas d'un montant notable. (Attendez, c'est une auto-contredire!)

la précision obtenue peut être vue ici:

-- Version 2 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)+")";
}

Usages:

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 Universelle --

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

-- Version 2 Universal 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 RGB et Hex. Celle-ci n'est pas vraiment différente de l'autre version Uni fournie 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 la compressez en une ligne. bien sûr, si vous n'avez pas besoin de l'utiliser de façon interchangeable entre RGB et Hex, alors vous n'avez pas besoin D'un universel version comme cela de toute façon, lol. il suffit d'utiliser une des versions beaucoup plus petites et plus rapides ci-dessus; approprié pour votre arrangement de couleur. Aller de l'avant... À certains égards, il est un peu plus rapide, à certains égards, il est un peu plus lent. Je n'ai pas fait d'analyse finale de vitesse. 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, lorsque le mélange, vous pouvez utiliser des nombres négatifs. Ils vont juste être convertis en nombres positifs.

Sans plus tarder:

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 *

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

-- version PHP-HEX (by 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);
}


-- mise à JOUR -- Version 3.1 Universelle --

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

Dans quelques mois, il aura encore été une année depuis la dernière version universelle. Si... grâce à sricks commentaire perspicace. J'ai décidé de le prendre au prochain niveau, encore une fois. 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 supprimer le décodage à 3 chiffres, vous pouvez le faire descendre à environ 1200 octets et son 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);
}

Jouer avec la version 3.1: jsfiddle > shadeBlendConvert Exemple

le calcul de base de cette version est le même qu'avant. Mais, j'ai fait quelques modification majeure. Cela a permis une fonctionnalité et un contrôle beaucoup plus grands. Il convertit maintenant intrinsèquement RGB2Hex et Hex2RGB.

toutes les anciennes fonctionnalités de v2 ci-dessus devraient encore être ici. J'ai essayé de tester tout ça, merci de poster un commentaire si vous trouvez quelque chose de mal. Quoi qu'il en soit, voici les nouvelles fonctionnalités:

  • Accepte les codes de couleur hexadécimaux à 3 chiffres (ou 4 chiffres), sous la forme #RGB (ou #ARGB). Elle permettra d'élargir. supprimer la ligne marquée de //3 digit pour supprimer cette caractéristique.
  • 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 si c'était normal d'un canal de couleur). Si une seule des deux couleurs a un canal alpha, cet alpha sera passé au résultat. Cela permet de mélanger/ombrager une couleur transparente tout en maintenant le transparent niveau. Ou, si le niveau transparent devrait se fondre aussi, assurez-vous que les deux couleurs ont des alphas. L'ombrage passera par le canal alpha, si vous voulez l'ombrage de base qui mélange également le canal alpha, puis utilisez rgb(0,0,0,1) ou rgb(255,255,255,1) comme votre couleur to (ou leurs équivalents hexadécimaux). Pour les couleurs RVB, le canal alpha sera arrondi à 4 décimales.
  • Les conversions
  • RGB2Hex et Hex2RGB sont maintenant implicites lorsqu'on utilise le mélange. Le résultat couleur toujours être sous la forme de la couleur to , si on existe. S'il n'y a pas de couleur to , alors passer 'c' en tant que la couleur to et il va ombre et convertir. Si la conversion seulement est désirée, alors passer 0 comme le pourcentage aussi bien.
  • Une fonction secondaire est ajouté au global. sbcRip peut passer une couleur hex ou rbg et renvoie un objet contenant cette information de couleur. Son sous la forme: {0:R,1:G,2:B,3:A} . Où R G et B ont une portée 0 à 255 . Et quand il n'y a pas d'alpha: A est -1 . Autrement: A a une portée 0.0000 à 1.0000 .
  • la vérification des erreurs mineures a été ajoutée. Il n'est pas parfait. Il peut encore l'écrasement. Mais il attrapera des trucs. Fondamentalement, si la structure est erronée d'une certaine manière ou si le pourcentage n'est pas un nombre ou hors champ, il retournera null . Un exemple: shadeBlendConvert(0.5,"salt") = null , où comme il pense #salt est une couleur valide. supprimer les quatre lignes marquées //ErrorCheck pour supprimer cette caractéristique.

les Usages:

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 à dire que c'est fait... encore...

PT

--Modifier: a changé la version 3 pour utiliser let , et une fonction de flèche, et ajouté this à sbcRip appels.

----===<| MODIFICATION MAJEURE(3/9/18) |>===----

j'ai tellement honte! apparemment, je n'utilise pas les chaînes alpha dans mes propres projets... ET... apparemment, j'ai fait de terribles tests. La Version 3 n'a pas lu ni écrit les couleurs avec les canaux alpha correctement. Il y avait quelques points que je viens d'avoir faux ou n'a jamais réellement appris:

  • Hex couleurs avec alpha #RGBA (pas #ARGB). La Version 3 lisait et écrivait à l'envers.
  • "15192360920 de couleurs RGB avec des alphas doit être rgba() et non pas rgb() ; la version 3 ne jamais sortie rgba() .
  • Version 3 n'a pas accepté rgba() mais a accepté alphas dans rgb() , ce qui ne devrait pas se produire.

I tout à l'heure a remplacé la Version 3 par la Version 3.1 où ces questions sont abordées. Je ne l'ai pas posté comme une fonction séparée ici; vu que l'ancienne Version 3 devrait être supprimé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:

  • se lit correctement et écrit des couleurs avec des canaux alpha. Les deux Hex et RGB.
  • la couleur to accepte maintenant une couleur de chaîne ou une falsy (qui peut encore être undefined ).
  • la fonction est maintenant constante.

... Je suis content d'avoir hésité à dire que c'était encore fait. Nous voici, une autre année ou deux plus tard ... encore le perfectionner...

PT

772
répondu 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 D'Allégement:

shadeColor("#63C6FF",40);

Exemple Noirci:

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

j'ai essayé votre fonction et il y a eu un petit bug: si une valeur finale 'r' est à 1 chiffre seulement, le résultat apparaît comme: 'a0a0a' quand la bonne valeur est '0a0a0a', par exemple. Je l'ai juste corrigé rapidement en ajoutant ceci à la place 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;

ce n'est peut-être pas si beau, mais ça fait le travail. Great function, BTW. Juste ce dont j'avais besoin. :)

4
répondu Cool Acid 2012-01-06 20:13:50

avez-vous pensé à une conversion rgb > hsl? alors déplace 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

MODIFIER le lien ci-dessus n'est plus valide. Vous pouvez voir git hub pour le page source ou le gist

alternativement un autre empilage question pourrait être un bon endroit pour regarder.


même si ce N'est pas le bon choix pour le PO, ce qui suit est un approximation du code que je suggérais à l'origine. (En supposant que vous avez des fonctions de conversion rgb/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 des fonctions hslToRgb et rgbToHsl .
  2. le paramètre colorValue est une chaîne de caractères sous la forme #RRGGBB

bien que si nous parlons de css Il y a une syntaxe pour spécifier hsl / hsla pour IE9/Chrome/Firefox.

3
répondu James Khoury 2017-05-23 12:26:36

C'est ce que j'ai utilisé basé sur votre fonction. Je préfère utiliser les pas plutôt que le pourcentage parce que c'est plus intuitif pour moi.

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

de toute façon, voici ma modification, merci pour votre fonction originale.

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
répondu Eric Sloan 2018-07-16 04:06:26

la méthode suivante vous permettra d'alléger ou d'obscurcir la valeur d'exposition d'une chaîne de couleur hexadécimale (hexadécimal (Hex):

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(), passer dans 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
répondu Jason Williams 2017-12-07 22:36:26

je voulais changer une couleur à un niveau de luminosité spécifique - peu importe la luminosité de la couleur était avant - voici une fonction JS simple qui semble bien fonctionner, bien que je suis sûr qu'il pourrait être plus court

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
répondu Torbjörn Josefsson 2018-03-07 10:37:42

C# Version... notez que je reçois des chaînes de couleurs dans ce format #FF12AE34, et que je dois 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
répondu user1618171 2014-09-23 20:14:19

Comment faire simple couleur d'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
répondu jsebestyan 2015-05-17 19:15:50

j'ai fait un port de l'excellente bibliothèque xcolor pour supprimer sa dépendance jQuery. Il y a une tonne de fonctions, y compris l'éclaircissement et assombrissement des couleurs.

en fait, convertir hex en RVB est une fonction complètement séparée des couleurs claires ou obscurcissantes. Gardez les choses sèches s'il vous plaît. Dans tous les cas, une fois que vous avez une couleur RVB, Vous pouvez juste 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
répondu B T 2017-01-17 02:52:06

j'ai longtemps voulu 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
répondu user2655360 2017-08-29 03:00:36