Domanda

Motivazione

Vorrei trovare un modo per prendere un colore arbitrario e schiarirlo di alcune sfumature, in modo da poter creare in modo programmatico un gradiente graduale dall'unico colore a una versione più chiara. Il gradiente verrà utilizzato come sfondo in un'interfaccia utente.

Possibilità 1

Ovviamente posso semplicemente dividere i valori RGB e aumentarli singolarmente di una certa quantità. È davvero quello che voglio?

Possibilità 2

Il mio secondo pensiero è stato quello di convertire RGB in HSV / HSB / HSL (Tonalità, Saturazione, Valore / Luminosità / Luminosità), aumentare un po 'la luminosità, diminuire un po' la saturazione e poi riconvertirla in RGB. Questo avrà l'effetto desiderato in generale?

È stato utile?

Soluzione

Vorrei scegliere la seconda opzione. In generale, lo spazio RGB non è molto utile per la manipolazione del colore (creazione di transizione da un colore all'altro, schiarimento / scurimento di un colore, ecc.). Di seguito sono riportati due siti che ho trovato con una rapida ricerca per convertire da / a RGB in / da HSL:

Altri suggerimenti

Come Wedge ha detto , vuoi moltiplicare per rendere le cose più luminose, ma che Funziona solo fino a quando uno dei colori diventa saturo (cioè raggiunge 255 o più). A quel punto, puoi semplicemente bloccare i valori a 255, ma cambierai leggermente la tonalità man mano che diventi più chiaro. Per mantenere la tonalità, si desidera mantenere il rapporto tra (medio-basso) / (più alto-basso).

Ecco due funzioni in Python. Il primo implementa l'approccio ingenuo che blocca i valori RGB a 255 se vanno oltre. Il secondo ridistribuisce i valori in eccesso per mantenere intatta la tonalità.

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)

Ho creato un gradiente a partire dal valore RGB (224.128,0) e moltiplicandolo per 1.0, 1.1, 1.2, ecc. fino a 2.0. La metà superiore è il risultato usando clamp_rgb e la metà inferiore è il risultato con redistribute_rgb . Penso che sia facile vedere che la ridistribuzione degli overflow dà un risultato molto migliore, senza dover lasciare lo spazio colore RGB.

Gradiente di leggerezza con bloccaggio (in alto) e ridistribuzione (in basso)

Per confronto, ecco lo stesso gradiente negli spazi colore HLS e HSV, implementato da colorsys . È stato modificato solo il componente L e il bloccaggio è stato eseguito sui valori RGB risultanti. I risultati sono simili, ma richiedono conversioni dello spazio colore per ogni pixel.

Gradiente di leggerezza con HLS (in alto) e HSV (in basso)

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

L'ho usato dappertutto.

Classe ControlPaint nello spazio dei nomi System.Windows.Forms ha metodi statici Light and Dark:

public static Color Dark(Color baseColor, float percOfDarkDark);

Questi metodi utilizzano l'implementazione privata di HLSColor. Vorrei che questa struttura fosse pubblica e in System.Drawing.

In alternativa, è possibile utilizzare GetHue, GetSaturation, GetBrightness su Color struct per ottenere componenti HSB. Sfortunatamente, non ho trovato la conversione inversa.

Converti in RGB e interpola linearmente tra il colore originale e il colore target (spesso bianco). Quindi, se vuoi 16 tonalità tra due colori, fai:


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

Per ottenere una versione più chiara o più scura di un determinato colore, è necessario modificarne la luminosità. Puoi farlo facilmente anche senza convertire il tuo colore in HSL o HSB. Ad esempio per rendere un colore più chiaro puoi usare il seguente codice:

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 hai bisogno di maggiori dettagli, leggi la storia completa sul mio blog .

In precedenza era stata posta una domanda molto simile, con risposte utili: Come posso determinare più scuro o variante di colore più chiara di un determinato colore?

Risposta breve: moltiplica i valori RGB per una costante se hai solo bisogno di "abbastanza buono", traduci in HSV se hai bisogno di precisione.

Ho usato la risposta di Andrew e la risposta di Mark per rendere questo (dal 1/2013 senza intervallo input per 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) }
}

inserisci qui la descrizione dell'immagine

La conversione in HS (LVB), l'aumento della luminosità e la riconversione in RGB è l'unico modo per schiarire in modo affidabile il colore senza influenzare i valori di tonalità e saturazione (cioè per schiarire il colore solo senza cambiarlo in altro modo) .

L'ho fatto in entrambi i modi: ottieni risultati molto migliori con Possibilità 2.

Qualsiasi semplice algoritmo che costruisci per Possibility 1 probabilmente funzionerà bene solo per un intervallo limitato di sature iniziali.

Dovresti esaminare Poss 1 se (1) puoi limitare i colori e le luminosità usati e (2) stai eseguendo molto il calcolo in un rendering.

La generazione dello sfondo per un'interfaccia utente non richiede molti calcoli dell'ombreggiatura, quindi suggerisco Poss 2.

-Al.

Se vuoi produrre una sfumatura sfumata, suggerirei la seguente ottimizzazione: Invece di fare RGB- > HSB- > RGB per ogni singolo colore, dovresti solo calcolare il colore target. Una volta che conosci l'RGB di destinazione, puoi semplicemente calcolare i valori intermedi nello spazio RGB senza dover convertire avanti e indietro. Se calcoli una transizione lineare dell'uso, dipende da te una sorta di curva.

Metodo 1: convertire RGB in HSL, regolare HSL, riconvertire in RGB.

Metodo 2: Lerp i valori di colore RGB - http: //en.wikipedia.org/wiki/Lerp_(computing)

Vedi la mia risposta a questa domanda simile per un'implementazione C # del metodo 2.

Fai finta che tu abbia mescolato l'alfa al bianco:

oneMinus = 1.0 - amount
r = amount + oneMinus * r
g = amount + oneMinus * g
b = amount + oneMinus * b

dove importo è compreso tra 0 e 1, con 0 che restituisce il colore originale e 1 che restituisce bianco.

Potresti voler fonderti con qualunque sia il colore di sfondo se stai schiarendo per mostrare qualcosa di disabilitato:

oneMinus = 1.0 - amount
r = amount * dest_r + oneMinus * r
g = amount * dest_g + oneMinus * g
b = amount * dest_b + oneMinus * b

dove (dest_r, dest_g, dest_b) è il colore da miscelare e importo è compreso tra 0 e 1, con zero che restituisce (r, g, b) e 1 di ritorno (dest.r, dest.g, dest.b)

Non ho trovato questa domanda fino a quando non è diventata una domanda correlata alla mia domanda originale.

Tuttavia, usando le intuizioni di queste grandi risposte. Ho messo insieme una bella funzione a due linee per questo:

Schiarisci o scurisci a livello di codice un colore esadecimale (o RGB, e fondere i colori)

È una versione del metodo 1. Ma tenendo conto della saturazione eccessiva. Come ha detto Keith nella sua risposta sopra; usa Lerp per risolvere apparentemente lo stesso problema menzionato da Mark, ma senza ridistribuzione. I risultati di shadeColor2 dovrebbero essere molto più vicini a farlo nel modo giusto con HSL, ma senza spese generali.

Un po 'in ritardo per la festa, ma se usi javascript o nodejs , puoi usare libreria tinycolor e manipola il colore nel modo che preferisci:

tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d" 

Avrei provato prima il numero 1, ma # 2 suona abbastanza bene. Prova a farlo da solo e vedi se sei soddisfatto dei risultati, sembra che ti ci vorranno forse 10 minuti per montare un test.

Tecnicamente, non penso neanche che sia corretto, ma credo che tu voglia una variante dell'opzione # 2. Il problema è che si è trattato di RGB 990000 e "alleggerimento". sarebbe davvero solo aggiungere sul canale rosso (valore, luminosità, luminosità) fino a quando non si arriva a FF. Dopodiché (rosso fisso), eliminerebbe la saturazione per passare al bianco solido.

Le conversioni diventano fastidiose, soprattutto perché non puoi andare direttamente da e verso RGB e Lab, ma penso che tu voglia davvero separare i valori di crominanza e luminosità e modificare semplicemente la luminosità per ottenere davvero ciò che desideri.

Troverai il codice da convertire tra gli spazi colore nel -tools ruby ??library

Ho un post sul blog che mostra come farlo in Delphi. È piuttosto semplice perché le funzioni ColorRGBToHSL e ColorHLSToRGB fanno parte della libreria standard.

Ecco un esempio di schiarimento di un colore RGB in 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))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top