Programaticamente Clarear ou Escurecer uma cor hexadecimal (ou rgb e misturar colors)

Aqui está uma function em que eu estava trabalhando para clarear ou escurecer uma cor hexadecimal por um valor específico. Basta passar uma string como "3F6D2A" para a cor ( col ) e um inteiro base10 ( amt ) para a quantidade para clarear ou escurecer. Para escurecer, passe um número negativo (ou seja, -20).

A razão para eu fazer isso foi por causa de todas as soluções que encontrei, até agora, eles pareciam complicar demais a questão. E eu senti que isso poderia ser feito com apenas algumas linhas de código. Por favor, deixe-me saber se você encontrar algum problema ou se tiver algum ajuste a ser feito para acelerar.

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

Para o desenvolvimento use aqui é uma versão mais fácil de ler:

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

E finalmente uma versão para lidar com colors que podem (ou não) ter o “#” no começo. Ajuste adicional para valores de cor impróprios:

 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 > 8) & 0x00FF) + amt; if ( b > 255 ) b = 255; else if (b  255 ) g = 255; else if ( g < 0 ) g = 0; return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16); } 

OK, agora não é apenas um par de linhas, mas parece muito mais simples e se você não está usando o “#” e não precisa verificar colors fora do intervalo, é apenas um par de linhas.

Se não estiver usando o “#”, você pode simplesmente adicioná-lo no código como:

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

Eu acho que a minha principal questão é, estou correto aqui? Isso não abrange algumas situações (normais)?

TL; DR? –Querer simples clarear / escurecer (sombreamento)? Pule para baixo para a versão 2, escolha um para RGB ou Hex. –Quer um shader / liquidificador / conversor cheio de resources com errorcheck e alpha e 3 dígitos hex? Use a versão 3 na parte inferior.

Jogue com a versão 3.1: jsfiddle> shadeBlendConvert Example

Versão 3.1 no GitHub: Goto GitHub> PJs> pSBC


Depois de pensar um pouco, decidi responder minha própria pergunta. Um ano e meio depois. Esta foi realmente uma aventura com ideias de vários usuários úteis, e agradeço a todos! Este é para o time! Embora não seja necessariamente a resposta que eu estava procurando. Porque se o que James Khoury está dizendo é verdade, então não há matemática hexadecimal verdadeira em javascript, eu tenho que usar decimais, essa conversão dupla é necessária. Se nós fizermos essa suposição, então esta é provavelmente a maneira mais rápida que eu vi (ou posso pensar) para clarear (adicionar branco) ou escurecer (adicionar preto) uma cor RBG arbitrária por porcentagem. Também é responsável pelos problemas que o Cool Acid mencionou em sua resposta a essa pergunta (é 0s). Mas esta versão chama toString apenas uma vez. Isso também é considerado fora do intervalo (aplicará 0 e 255 como limites).

Mas cuidado, a input de cor tem que ser EXATAMENTE 7 caracteres, como #08a35c . (ou 6 se estiver usando a versão superior)

Obrigado a Pablo pela inspiração e ideia de usar porcentagem. Por isso vou manter o nome da function igual! ri muito! No entanto, este é diferente, pois normaliza o percentual para 255 e, assim, adicionando a mesma quantidade a cada cor (mais branco). Se você passar em 100 por percent isso tornará sua cor branca pura. Se você passar em 0 por percent , nada acontecerá. Se você passar em 1 por percent ele adicionará 3 tons a todas as colors (2,55 tons por 1%, arredondados). Então você realmente está passando uma porcentagem de branco (ou preto, use negativo). Portanto, esta versão permite que você ilumine o vermelho puro (FF0000), por exemplo.

Eu também usei uma visão da resposta de Keith Mashinter para esta pergunta: Como converter um decimal em hexadecimal em JavaScript?

Eu removi alguns parênteses aparentemente desnecessários. (como no double ternary statement e no crafting G) Não tenho certeza se isso vai mexer com a precedência do operador em alguns ambientes. Testado bem no 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, se você quiser lidar com o "#":

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

Como é isso para duas linhas de código?

EDIT: Corrigir B ​​<-> G swap goof. Obrigado svachalek!


- ATUALIZAÇÃO - Versão 2 com Blending -

Pouco mais de um ano depois, mais uma vez, e ainda continua. Mas desta vez eu acho que está feito. Observando os problemas mencionados sobre não usar HSL para clarear corretamente a cor. Existe uma técnica que elimina a maior parte dessa imprecisão sem ter que converter para HSL. O principal problema é que um canal de cor ficará totalmente saturado antes do resto da cor. Causando uma mudança na tonalidade depois desse ponto. Eu encontrei estas perguntas aqui , aqui e aqui, que me colocaram no caminho certo. O post de Mark Ransom me mostrou a diferença, e o post de Keith me mostrou o caminho. Lerp é o salvador. É o mesmo que misturar colors, então criei uma function blendColors também.


TL; DR - Para simples clarear / escurecer use esta function shadeColor2 abaixo. Ou sua contraparte RGB shadeRGBColor mais abaixo, e me dê um voto. Mas, se você quiser alguma e / ou todas as guloseimas. Como a capacidade de usar colors RGB e Hex, verificação de erros, decodificação hexadecimal de 3 dígitos, mesclagem, canais alfa e conversões RGB2Hex / Hex2RGB. Então, pule para a versão 3 do shadeBlendConvert para pegar todos os sinos e assobios e me dê dois votos. Você pode então excluir algumas linhas para remover alguns desses resources, se desejar. E você recebe uma votação se lembrar que a versão 1 do shadeColor1 acima está obsoleta para todos os usos.


Então, sem mais delongas:

-Versão 2 hexadecimal

 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((tR)*p)+R)*0x10000+(Math.round((tG)*p)+G)*0x100+(Math.round((tB)*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); } 

Mais delongas:

Não há verificação de erros, portanto, os valores transmitidos fora do intervalo causarão resultados inesperados. Além disso, a input de cor tem que ser EXATAMENTE 7 caracteres, como #08a35c . Mas todas as outras coisas ainda estão aqui como limite de faixa de saída (saídas de 00 a FF), preenchimento (0A), alças # e uso em colors sólidas, como #FF0000 .

Esta nova versão do shadeColor leva em um float para seu segundo parâmetro. Para shadeColor2 o intervalo válido para o segundo parâmetro (percentual) é de -1.0 a 1.0 .

E para blendColors o intervalo válido para o terceiro parâmetro (por cento) é de 0.0 a 1.0 , negativos não permitidos aqui.

Esta nova versão não está mais recebendo uma porcentagem de branco puro, como a versão antiga. Está tomando uma porcentagem da DISTÂNCIA da cor dada ao branco puro. Na versão antiga, era fácil saturar a cor e, como resultado, muitas colors computavam a branco puro ao usar uma porcentagem considerável. Esta nova maneira, só computa para branco puro se você passar em 1.0 , ou preto puro, use -1.0 .

Chamar blendColors(color, "#FFFFFF", 0.5) é o mesmo que shadeColor2(color,0.5) . Bem como, blendColors(color,"#000000", 0.5) é o mesmo que shadeColor2(color,-0.5) . Apenas um toque mais lento.

shadeColor2 é mais lento que shadeColor1 , mas não por uma quantidade notável. (Espere, isso é uma afirmação contraditória!)

A precisão obtida pode ser vista aqui:

- Versão 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((tR)*p)+R)+","+(Math.round((tG)*p)+G)+","+(Math.round((tB)*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)+")"; } 

Usos:

 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) 

- Versão 2 Universal 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); } 

Uso:

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

- Versão 2 Universal B -

Ok, tudo bem! A popularidade desta resposta me fez pensar que eu poderia fazer uma versão Universal muito melhor disso. Então aqui vai você! Esta versão é uma function All-In-One para copiar / colar shader / blender para colors RGB e Hex. Este não é realmente diferente do que a outra versão da Uni fornecida acima. Exceto que é muito menor e apenas uma function para colar e usar. Eu acho que o tamanho foi de cerca de 1.592 caracteres para 557 caracteres, se você compactar em uma linha. Claro, se você não precisa usá-lo de forma intercambiável entre RGB e Hex, então você não precisa de uma versão Universal como esta, lol. Basta usar uma das versões muito menores e mais rápidas acima; apropriado para o seu esquema de colors. Seguindo em frente ... De certa forma é um pouco mais rápido, em alguns aspectos é um pouco mais lento. Eu não fiz nenhuma análise final de teste de velocidade. Existem duas diferenças de uso: primeiro, a porcentagem é agora o primeiro parâmetro da function, em vez do último. Em segundo lugar, quando misturando, você pode usar números negativos. Eles serão convertidos em números positivos.

Não há mais barulho:

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

Uso:

 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 

Agora pode ser perfeito! ;) @ Mevin

* V2 OUTRAS LINGUAGENS *

- Extensão Swift - RGB (por 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 = (tr)*p+r g = (tg)*p+g b = (tb)*p+b return UIColor(red: r, green: g, blue: b, alpha: a) } } 

- Versão PHP - HEX (por 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); } 

- ATUALIZAÇÃO - Versão 3.1 Universal -

(Isso foi adicionado à minha biblioteca no GitHub )

Em alguns meses, terá sido mais um ano desde a última versão universal. Então ... graças ao comentário perspicaz de sricks . Eu decidi levá-lo para o próximo nível, novamente. Não é mais o demônio de velocidade de duas linhas como tinha começado, lol. Mas, pelo que faz, é bastante rápido e pequeno. Seus cerca de 1600 bytes. Se você remover o ErrorChecking e remover a decodificação de 3 dígitos, poderá reduzi-lo para cerca de 1200 bytes e será mais rápido. Isso é muito poder em um K. Imaginem, você poderia carregar isso em um Commodore64 e ainda ter espaço para mais 50 deles! (Desconsiderando o fato de que o mecanismo JavaScript é maior que 63k)

Aparentemente, havia mais trabalho a ser feito:

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

Jogue com a versão 3.1: jsfiddle> shadeBlendConvert Example

A matemática principal desta versão é a mesma de antes. Mas eu fiz algumas grandes refatorações. Isso permitiu maior funcionalidade e controle. Agora, ele converte inerentemente RGB2Hex e Hex2RGB.

Todos os resources antigos da v2 acima ainda devem estar aqui. Eu tentei testar tudo, por favor poste um comentário se você encontrar algo errado. De qualquer forma, aqui estão os novos resources:

  • Aceita códigos de colors HEX de 3 dígitos (ou 4 dígitos), no formato #RGB (ou #ARGB). Isso os expandirá. Exclua a linha marcada com //3 digit para remover esse recurso.
  • Aceita e combina canais alfa. Se a cor de origem ou a cor tiver um canal alfa, o resultado terá um canal alfa. Se ambas as colors tiverem um canal alfa, o resultado será uma mistura dos dois canais alfa usando a porcentagem fornecida (como se fosse um canal de cor normal). Se apenas uma das duas colors tiver um canal alfa, esse alfa será passado apenas para o resultado. Isso permite misturar / sombrear uma cor transparente, mantendo o nível transparente. Ou, se o nível transparente também se misturar, verifique se as duas colors têm alfas. O sombreamento passará pelo canal alfa, se você quiser um sombreamento básico que também mescla o canal alfa, use rgb(0,0,0,1) ou rgb(255,255,255,1) como sua cor (ou seus equivalentes hexadecimais). Para colors RGB, o canal alfa resultante será arredondado para 4 casas decimais.
  • As conversões RGB2Hex e Hex2RGB agora estão implícitas ao usar a mesclagem. A cor resultante sempre estará na forma da cor, se existir. Se não houver cor, passe em 'c' como cor e ela será sombreada e convertida. Se somente a conversão for desejada, passe 0 como a porcentagem também.
  • Uma function secundária é adicionada ao global também. sbcRip pode receber uma cor hexadecimal ou rbg e retorna um object contendo essa informação de cor. Está na forma: {0:R,1:G,2:B,3:A} . Onde RG e B têm o intervalo de 0 a 255 . E quando não há alfa: A é -1 . Caso contrário: A tem um intervalo de 0.0000 a 1.0000 .
  • Verificação de erros menor foi adicionada. Não é perfeito. Ainda pode falhar. Mas vai pegar algumas coisas. Basicamente, se a estrutura estiver errada de alguma forma ou se a porcentagem não for um número ou fora do escopo, ela retornará null . Um exemplo: shadeBlendConvert(0.5,"salt") = null , onde, como se pensa, #salt é uma cor válida. Exclua as quatro linhas marcadas com //ErrorCheck para remover esse recurso.

Usos:

 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} 

Eu agora hesito em chamar isso de novo ... de novo ...

PT

--EDIT: Versão 3 comutada para usar let e uma function de seta e adicionada a sbcRip calls.

---- === <| EDITOR PRINCIPAL (3/9/18) |> === ----

Estou tão envergonhada! (e surpreso que ninguém mencionou isso) Aparentemente eu não uso canais alfa em meus próprios projetos ... E ... aparentemente eu fiz testes terríveis. A versão 3 não leu nem gravou colors com canais alfa corretamente. Houve alguns pontos que eu ou tinha errado ou nunca realmente aprendi:

  • As colors hexadecimais com alfa são #RGBA (não #ARGB). A versão 3 estava lendo e escrevendo isso de trás para frente.
  • As colors RGB com alfas devem ser rgba() e não rgb() ; versão 3 nunca saída rgba() .
  • A versão 3 não aceitou rgba() mas aceitou alfas em rgb() , o que não deveria acontecer.

Acabei de replace a versão 3 com a versão 3.1, onde esses problemas são abordados. Eu não postei isso como uma function separada aqui; vendo como a versão antiga 3 deve ser removida da existência e substituída por esta. E foi isso que eu fiz. A versão 3 acima é, na verdade, a versão 3.1.

Todos os resources antigos acima ainda estão aqui com essas atualizações:

  • Leituras e gravações adequadas de colors com canais alfa. Ambos Hex e RGB.
  • A cor agora aceita uma cor de string ou uma falsy (que ainda pode ser undefined ).
  • A function agora é constante.

Estou feliz por ter hesitado em chamar de novo. Aqui estamos nós, mais um ano depois ... ainda aperfeiçoando ...

PT

Eu fiz uma solução que funciona muito bem para mim:

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

Exemplo clarear:

 shadeColor("#63C6FF",40); 

Exemplo de Escurecimento:

 shadeColor("#63C6FF",-40); 

Eu tentei a sua function e houve um pequeno erro: Se algum valor ‘r’ final é apenas 1 dígito, o resultado aparece como: ‘a0a0a’ quando o valor correto é ‘0a0a0a’, por exemplo. Eu apenas corrigi-lo rapidamente, adicionando isso em vez do seu retorno:

 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; 

Talvez não seja tão bom, mas faz o trabalho. Ótima function, BTW. Apenas o que eu precisava. 🙂

Você já pensou em uma conversão rgb> hsl? então apenas mova a luminosidade para cima e para baixo? é assim que eu iria.

Um rápido olhar para alguns algoritmos me trouxe os seguintes sites.

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 o link acima não é mais válido. Você pode ver o hub do git para a fonte da página ou a essência

Como alternativa, outra pergunta do StackOverflow pode ser um bom lugar para procurar.


Mesmo que esta não seja a escolha certa para o OP, segue-se uma aproximação do código que eu estava originalmente sugerindo. (Supondo que você tenha funções de conversão 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; } 

Isso pressupõe:

  1. Você tem funções hslToRgb e rgbToHsl .
  2. O parâmetro colorValue é uma string no formato #RRGGBB

Embora, se estamos discutindo css, há uma syntax para especificar hsl / hsla para o IE9 / Chrome / Firefox.

Isso é o que eu usei com base na sua function. Eu prefiro usar etapas acima do percentual porque é mais intuitivo para mim.

Por exemplo, 20% de um valor de 200 azuis é muito diferente de 20% de um valor de 40 azuis.

De qualquer forma, aqui está minha modificação, obrigado pela sua function original.

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

O método a seguir permitirá clarear ou escurecer o valor de exposição de uma sequência de colors hexadecimal (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"); } } 

Para o último valor de parâmetro em GetHexFromRGB (), passe um valor duplo em algum lugar entre -1 e 1 (-1 é preto, 0 não é alterado, 1 é branco):

 // 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%; 

I wanted to change a color to a specific brightness level – no matter what brightness the color was before – here’s a simple JS function that seems to work well, although I’m sure it could be shorter

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

C# Version… note that I am getting color strings in this format #FF12AE34, and need to cut out the #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); } 

How to simple shade color in PHP?

  

I made a port of the excellent xcolor library to remove its jQuery dependency. There are a ton of functions in there including lightening and darkening colors.

Really, converting hex to RGB is a completely separate function from lightening or darkening colors. Keep things DRY please. In any case, once you have an RGB color, you can just add the difference between the light level you want and the light level you have to each of the RGB values:

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

See https://github.com/fresheneesz/xolor for more of the source.

I’ve long wanted to be able to produce tints/shades of colours, here is my JavaScript solution:

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