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?

Foi útil?

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:

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.

gradiente de leveza com aperto (topo) e de redistribuição (inferior)

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.

gradiente de leveza com HLS (topo) e o HSV (inferior)

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

enter descrição da imagem aqui

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))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top