Programaticamente Clarear a cores
-
02-07-2019 - |
Pergunta
Motivation
Eu gostaria de encontrar uma maneira de levar uma cor arbitrária e iluminá-lo alguns tons, para que eu possa programaticamente criar um gradiente agradável da uma cor para uma versão mais leve. O gradiente será usada como um fundo em uma interface do usuário.
Possibilidade 1
Obviamente, eu posso apenas dividir os valores RGB e aumentá-los individualmente por um determinado montante. É este realmente o que eu quero?
Possibilidade 2
Meu segundo pensamento foi para converter o RGB para HSV / HSB / HSL (Hue, Saturation, Value / Brilho / Luminosidade), aumentar o brilho um pouco, diminuir a saturação um pouco, e depois convertê-lo de volta para RGB. Isso terá o efeito desejado em geral?
Solução
Gostaria de ir para a segunda opção. De um modo geral o espaço RGB não é realmente bom para fazer manipulação de cores (criando transição de uma cor para um outro, aliviando / escurecer uma cor, etc). Abaixo estão dois sites que eu encontrei com uma pesquisa rápida para converter de / para RGB para / de HSL:
- dos "Fundamentos de Computação Gráfica"
- algum código fonte em C # - deve ser fácil de adaptar-se a outras linguagens de programação .
Outras dicas
Como Wedge disse , você quer multiplicar para tornar as coisas mais brilhante, mas que só funciona até que uma das cores torna-se saturado (isto é, atinge 255 ou mais). Nesse ponto, você pode apenas apertar os valores a 255, mas você vai ser sutilmente mudando a tonalidade que você começa mais leve. Para manter o tom, você quer manter a relação de (meia-menor) / (maior-menor).
Aqui estão duas funções em Python. Os primeiros instrumentos a abordagem ingênua que apenas braçadeiras os valores RGB para 255 se passar por cima. O segundo redistribui os valores em excesso para manter a tonalidade intacta.
def clamp_rgb(r, g, b):
return min(255, int(r)), min(255, int(g)), min(255, int(b))
def redistribute_rgb(r, g, b):
threshold = 255.999
m = max(r, g, b)
if m <= threshold:
return int(r), int(g), int(b)
total = r + g + b
if total >= 3 * threshold:
return int(threshold), int(threshold), int(threshold)
x = (3 * threshold - total) / (3 * m - total)
gray = threshold - x * m
return int(gray + x * r), int(gray + x * g), int(gray + x * b)
I criado um gradiente começando com o valor RGB (224,128,0) e multiplicando-o por 1,0, 1,1, 1,2, etc., até 2,0. A metade superior é o resultado utilizando clamp_rgb
e a metade inferior é o resultado com redistribute_rgb
. Eu acho que é fácil ver que a redistribuição das transborda dá um resultado muito melhor, sem ter que deixar o espaço de cor RGB.
Para efeito de comparação, aqui está o mesmo gradiente nos espaços HLS e cor HSV, como implementado pelo Python colorsys
módulo. Somente o componente L
foi modificado, e de fixação foi realizada sobre os valores RGB resultante. Os resultados são semelhantes, mas exigem conversões espaço de cor para cada pixel.
Em C #:
public static Color Lighten(Color inColor, double inAmount)
{
return Color.FromArgb(
inColor.A,
(int) Math.Min(255, inColor.R + 255 * inAmount),
(int) Math.Min(255, inColor.G + 255 * inAmount),
(int) Math.Min(255, inColor.B + 255 * inAmount) );
}
Eu usei isso em todo o lugar.
ControlPaint classe no System.Windows.Forms namespace tem métodos estáticos claro e escuro:
public static Color Dark(Color baseColor, float percOfDarkDark);
Esses métodos usam implementação privada de HLSColor. Eu desejo que este struct era público e em System.Drawing.
Como alternativa, você pode usar GetHue, GetSaturation, GetBrightness em struct cores para obter componentes HSB. Infelizmente, eu não encontrou a conversão inversa.
Converter-lo para RGB e linearmente interpolate entre a cor original e a cor alvo (muitas vezes branco). Então, se você quiser 16 tons entre duas cores, você faz:
for(i = 0; i < 16; i++)
{
colors[i].R = start.R + (i * (end.R - start.R)) / 15;
colors[i].G = start.G + (i * (end.G - start.G)) / 15;
colors[i].B = start.B + (i * (end.B - start.B)) / 15;
}
A fim de obter uma versão mais leve ou mais escuro de uma determinada cor que você deve modificar o seu brilho. Você pode fazer isso facilmente, mesmo sem converter sua cor para HSL ou cor HSB. Por exemplo, para fazer uma cor mais clara, você pode usar o seguinte código:
float correctionFactor = 0.5f;
float red = (255 - color.R) * correctionFactor + color.R;
float green = (255 - color.G) * correctionFactor + color.G;
float blue = (255 - color.B) * correctionFactor + color.B;
Color lighterColor = Color.FromArgb(color.A, (int)red, (int)green, (int)blue);
Se você precisar de mais detalhes, ler a história completa no meu blog .
Uma questão muito semelhante, com respostas úteis, foi perguntado anteriormente: Como faço para determinar mais escuras ou mais mais leve variante de cor de uma determinada cor?
Resposta curta:. Multiplicar os valores RGB por uma constante, se você só precisa de "bom o suficiente", traduzir para HSV se você precisar de precisão
Eu usei a resposta de Andrew ea resposta de Mark para fazer este (a partir de 1/2013 nenhum intervalo entrada para ff).
function calcLightness(l, r, g, b) {
var tmp_r = r;
var tmp_g = g;
var tmp_b = b;
tmp_r = (255 - r) * l + r;
tmp_g = (255 - g) * l + g;
tmp_b = (255 - b) * l + b;
if (tmp_r > 255 || tmp_g > 255 || tmp_b > 255)
return { r: r, g: g, b: b };
else
return { r:parseInt(tmp_r), g:parseInt(tmp_g), b:parseInt(tmp_b) }
}
A conversão para HS (LVB), aumentando a luminosidade e, em seguida, a conversão de volta para RGB é a única maneira para iluminar de forma fiável a cor sem afectar os valores de tonalidade e saturação (isto é, a iluminar apenas a cor sem a alterar de qualquer outra forma) .
Já fiz isso em ambos os sentidos -. Você obter resultados muito melhores com Possibilidade 2
Qualquer algoritmo simples que você construir para Possibilidade 1 provavelmente funcionam bem apenas para uma gama limitada de iniciar saturações.
Você iria querer olhar para Poss 1 se (1) você pode restringir as cores e brilhos utilizados, e (2) você está realizando o cálculo muito em uma renderização.
Gerando o fundo para uma interface de usuário não vai precisar de muito muitos cálculos de sombreamento, então eu sugiro Poss 2.
-Al.
Se você quer produzir um gradiente fade-out, gostaria de sugerir o seguinte otimização: Ao invés de fazer RGB-> HSB-> RGB para cada cor individual só deve calcular a cor alvo. Depois de saber o alvo RGB, você pode simplesmente calcular os valores intermediários no espaço RGB sem ter de converter e para trás. Se você calcular uma transição linear de uso de algum tipo de curva é com você.
Método 1:. Convert RGB para HSL, ajuste HSL, converter de volta para RGB
Método 2: Lerp os valores de cores RGB - http: //en.wikipedia.org/wiki/Lerp_(computing)
Veja minha resposta a esta pergunta semelhante para um C # implementação do método 2.
Finja que você alfa misturado ao branco:
oneMinus = 1.0 - amount
r = amount + oneMinus * r
g = amount + oneMinus * g
b = amount + oneMinus * b
onde amount
é de 0 a 1, sendo que 0 devolver a cor original e 1 retornando branco.
Você pode querer misturar-se com qualquer que seja a cor de fundo é se você está iluminando a mostrar algo desativado:
oneMinus = 1.0 - amount
r = amount * dest_r + oneMinus * r
g = amount * dest_g + oneMinus * g
b = amount * dest_b + oneMinus * b
onde (dest_r, dest_g, dest_b)
é a cor que está sendo misturado com e amount
é de 0 a 1, com zero de retorno (r, g, b)
e 1 retornando (dest.r, dest.g, dest.b)
Eu não encontrei esta pergunta até depois tornou-se uma questão relacionada à minha pergunta inicial.
No entanto, usando uma visão de estes grandes respostas. I reunido uma boa função de dois forro para isso:
programaticamente clarear ou escurecer a cor hexadecimal (ou rgb, e as cores de mistura)
É uma versão do método 1. Mas com saturação mais tidos em conta. Como Keith disse em sua resposta acima; usar Lerp para resolver seemly o mesmo problema Mark mencionado, mas sem redistribuição. Os resultados do shadeColor2
deve ser muito mais perto de fazê-lo da maneira certa com HSL, mas sem a sobrecarga.
Um pouco atrasado para a festa, mas se você usar javascript
ou nodejs
, você pode usar tinycolor biblioteca e manipular a cor da maneira que quiser:
tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d"
Eu teria tentado número # 1 em primeiro lugar, mas # 2 sons muito bom. Tente fazê-lo você mesmo e veja se você está satisfeito com os resultados, parece que ele vai levá-lo talvez 10 minutos para chicotear acima de um teste.
Tecnicamente, eu não acho que qualquer um é correto, mas eu acredito que você quer uma variante da opção # 2. O problema é que levado RGB 990000 e "relâmpago" seria realmente basta adicionar no canal Red (Value, Brilho, Lightness) até que você tem a FF. Depois disso (vermelho sólido), seria derrubar o saturação para percorrer todo o caminho para branco sólido.
As conversões ficar chato, especialmente desde que você não pode ir directo de e para RGB e Lab, mas eu acho que você realmente quer para separar os valores de crominância e luminância, e apenas modificar o luminence para realmente conseguir o que deseja.
Você vai encontrar o código para converter entre espaços de cores na cor -ferramentas biblioteca ruby ??
Eu tenho um blog que mostra como fazer isso em Delphi. Sua bastante simples, porque as funções ColorRGBToHSL e ColorHLSToRGB fazem parte da biblioteca padrão.
Aqui está um exemplo de aliviar uma cor RGB em Python:
def lighten(hex, amount):
""" Lighten an RGB color by an amount (between 0 and 1),
e.g. lighten('#4290e5', .5) = #C1FFFF
"""
hex = hex.replace('#','')
red = min(255, int(hex[0:2], 16) + 255 * amount)
green = min(255, int(hex[2:4], 16) + 255 * amount)
blue = min(255, int(hex[4:6], 16) + 255 * amount)
return "#%X%X%X" % (int(red), int(green), int(blue))