2008-09-18 11 views
40

Dato un colore di origine di qualsiasi tonalità dal sistema o dall'utente, mi piacerebbe un semplice algoritmo che posso usare per elaborare varianti più chiare o più scure del colore selezionato. Simile agli effetti utilizzati su Windows Live Messenger per lo styling dell'interfaccia utente.Come si determina la variante di colore più scuro o più chiaro di un determinato colore?

La lingua è C# con .net 3.5.

Risposta al commento: Il formato colore è (alfa) RGB. Con valori come byte o float.

Risposta di contrassegno: Per il contesto del mio utilizzo (alcuni semplici effetti dell'interfaccia utente), la risposta che sto contrassegnando come accettata è in realtà la più semplice per questo contesto. Tuttavia, ho rinunciato ai voti per le risposte più complesse e accurate. Chiunque esegua operazioni a colori più avanzate e trovi questo thread in futuro dovrebbe sicuramente controllarlo. Grazie COSÌ. :)

+0

Che formato è il colore? – UnkwnTech

+0

Solo per completare, attualmente lo spazio colore all'avanguardia per le conversioni e le interpolazioni dei colori (ad esempio, per creare una mappa colori percettivamente uniforme, ecc.) È CIELab. – heltonbiker

risposta

27

sufficiente moltiplicare i valori RGB per l'importo che si desidera modificare il livello. Se uno dei colori è già al valore massimo, non è possibile renderlo più luminoso (utilizzando comunque la matematica HSV)

Questo dà lo stesso risultato con molto meno matematica come passare a HSV e quindi modificare V. Questo dà lo stesso risultato del passaggio a HSL e quindi della modifica di L, a condizione che non si desideri iniziare a perdere la saturazione.

+0

Sì, è possibile rendere un colore più luminoso anche se non è possibile rendere più luminoso un singolo canale di colore. Perdere la saturazione è un effetto collaterale inevitabile. Vedi http://stackoverflow.com/a/141943/5987 –

+0

Moltiplicando i valori rgb non si fa nulla se il colore è nero – Dylanthepiguy

10

È possibile convertire i colori in HSL colore-spazio, manipolare lì e convertire nuovo al vostro spazio colore a scelta (molto probabilmente questo è RGB)

Accendino colori hanno un L-valore più alto, più scuro più basso

Ecco la roba rilevante e tutte le equazioni:

http://en.wikipedia.org/wiki/HSL_color_space

Un altro metodo è quello di interpolare semplicemente il colore con il bianco o nero. Ciò inoltre desaturerà il colore un po 'ma è più economico da calcolare.

+0

Questi calcoli tendono ad essere economici, ma una grande differenza è che la codifica richiesta è un onere per il programmatore. – heltonbiker

0

si Supponendo ottenere il colore come RGB, prima convertirlo in HSV (tonalità, saturazione, valore) spazio colore. Quindi aumentare/diminuire il valore per produrre una tonalità più chiara/più scura del colore. Quindi riconvertire in RGB.

20

HSV (Tonalità/Saturazione/Valore) chiamato anche HSL (Tonalità/saturazione/luminosità) è solo una rappresentazione di colore diverso.

Utilizzando questa rappresentazione è più facile regolare la luminosità. Quindi converti da RGB a HSV, schiarisci la 'V', quindi ricontrolla in RGB.

Di seguito è riportato un codice C per convertire

void RGBToHSV(unsigned char cr, unsigned char cg, unsigned char cb,double *ph,double *ps,double *pv) 
{ 
double r,g,b; 
double max, min, delta; 

/* convert RGB to [0,1] */ 

r = (double)cr/255.0f; 
g = (double)cg/255.0f; 
b = (double)cb/255.0f; 

max = MAXx(r,(MAXx(g,b))); 
min = MINx(r,(MINx(g,b))); 

pv[0] = max; 

/* Calculate saturation */ 

if (max != 0.0) 
    ps[0] = (max-min)/max; 
else 
    ps[0] = 0.0; 

if (ps[0] == 0.0) 
{ 
    ph[0] = 0.0f; //UNDEFINED; 
    return; 
} 
/* chromatic case: Saturation is not 0, so determine hue */ 
delta = max-min; 

if (r==max) 
{ 
    ph[0] = (g-b)/delta; 
} 
else if (g==max) 
{ 
    ph[0] = 2.0 + (b-r)/delta; 
} 
else if (b==max) 
{ 
    ph[0] = 4.0 + (r-g)/delta; 
} 
ph[0] = ph[0] * 60.0; 
if (ph[0] < 0.0) 
    ph[0] += 360.0; 
} 

void HSVToRGB(double h,double s,double v,unsigned char *pr,unsigned char *pg,unsigned char *pb) 
{ 
int i; 
double f, p, q, t; 
double r,g,b; 

if(s == 0) 
{ 
    // achromatic (grey) 
    r = g = b = v; 
} 
else 
{ 
    h /= 60;   // sector 0 to 5 
    i = (int)floor(h); 
    f = h - i;   // factorial part of h 
    p = v * (1 - s); 
    q = v * (1 - s * f); 
    t = v * (1 - s * (1 - f)); 
    switch(i) 
    { 
    case 0: 
     r = v; 
     g = t; 
     b = p; 
    break; 
    case 1: 
     r = q; 
     g = v; 
     b = p; 
    break; 
    case 2: 
     r = p; 
     g = v; 
     b = t; 
    break; 
    case 3: 
     r = p; 
     g = q; 
     b = v; 
    break; 
    case 4: 
     r = t; 
     g = p; 
     b = v; 
    break; 
    default:  // case 5: 
     r = v; 
     g = p; 
     b = q; 
    break; 
    } 
} 
r*=255; 
g*=255; 
b*=255; 

pr[0]=(unsigned char)r; 
pg[0]=(unsigned char)g; 
pb[0]=(unsigned char)b; 
} 
+6

[HSV e HSL sono cose diverse] (http://en.wikipedia.org/wiki/HSL_and_HSV). HSV è ** non ** chiamato anche HSL. –

+0

Ma HSV è talvolta chiamato HSB (luminosità). Che è ancora diverso da HSL, come dice @romkyns. –

+0

@KPexEA hai scritto "Converti da RGB a HSV, schiarisci la 'V', quindi converti in RGB." . Come faccio a * illuminare la parte 'V'?? Ho bisogno di generare' n' tonalità dello stesso colore. Le ombre dovrebbero essere sempre più luminose. – Geek

0

Se i colori sono in formato RGB (o, presumibilmente CMYK), è possibile utilizzare il metodo abbastanza grezzo di aumentare il valore di ogni componente del colore. Ad esempio, nei colori HTML sono rappresentati come tre numeri esadecimali a due cifre. # ff0000 ti darà un rosso brillante, che può essere sbiadito aumentando i valori dei componenti di G e B della stessa quantità, come # ff5555 (dà un rosso più chiaro). Presumibilmente per i colori Hue, Saturation and Lightness (HSL), puoi semplicemente aumentare il componente L, ma non posso dirlo con certezza; Sono meno familiare con questo spazio colore.

Come ho detto, però, questo metodo è piuttosto grezzo. Dai miei ricordi di Live Messenger, sembra che tu stia cercando di fare gradienti, che possono essere applicati davvero facilmente in Windows Presentation Foundation (WPF, parte di .NET 3.0). WPF supporta molti tipi diversi di pennello sfumato, inclusi gradienti lineari e radiali.

consiglio vivamente il libro di Adam Nathan Windows Presentation Foundation Unleashed come una buona e approfondita introduzione a WPF.

HTH

+0

# ff5555 non dà un rosso più chiaro, dà un rosso sbiadito. Meno saturi. Questo dà più luce, ma è più di un rosa che di un rosso più luminoso. – clahey

+0

In effetti si può usare un gradiente, ma è necessario fornire i colori per ogni arresto del gradiente. – Nidonocu

3

Se si utilizza colori RGB vorrei trasformare questo colore paramaters a HSL (tonalità, saturazione, luminosità), modificare il parametro di leggerezza e poi trasformare in RGB. Google in giro e troverai molti esempi di codice su come eseguire queste trasformazioni di rappresentazione del colore (da RGB a HSL e viceversa).

Questo è quello che ho trovato in fretta: http://bytes.com/forum/thread250450.html

0

Qualsiasi variazione di colore è meglio eseguita in HSL/HSV.

Un buon test è quello di interpolare tra due valori equivalenti nello spazio RGB e HSL spazio. La rampa nello spazio HSL sembra una progressione naturale. Nello spazio RGB sembra in genere piuttosto innaturale. HSL si adatta alla percezione dello spazio cromatico visivo molto meglio di RGB.

4

Sto indovinando che si sta utilizzando RGB con valori di byte (da 0 a 255) in quanto questo è molto comune in tutto il mondo.

Per luminosità, media i valori RGB con RGB di bianco. Oppure, per avere un po 'di controllo su quanto schiarire, mescolarli in una certa proporzione. Diamo f variano da 0,0 a 1,0, quindi:

Rnew = (1-f)*R + f*255 
Gnew = (1-f)*G + f*255 
Bnew = (1-f)*B + f*255 

Per più scuro, utilizzare il RGB del nero - che, essendo tutti gli zeri, rende più facile la matematica.

lascio i dettagli come la conversione del risultato in byte, che si sarebbe probabilmente vuole fare.

0

L'idea di conversione in HSV o qualche altro spazio colore sembra buono, e può essere necessario per il lavoro di colore preciso, ma per scopi ordinari l'errore di lavorare in RGB può non essere sufficiente alla materia. Inoltre, può essere un problema affrontare casi limite: RGB è uno spazio a forma di cubo, mentre HSV non lo è. Se si lavora con valori di byte, è possibile disporre di mapping molti-a-uno e uno-a-molti tra gli spazi. Questo può o non può essere un problema a seconda dell'applicazione. YMMV

14

Rich Newman discusses HSL color per quanto riguarda .NET System.Drawing.Color sul suo blog e anche provides an HSLColor class che fa tutto il lavoro per voi. Converti il ​​tuo System.Drawing.Color in un HSLColor, aggiungi/sottrai valori in Luminosity e riconvertilo in System.Drawing.Color per l'uso nella tua app.

9

Ho usato ControlPaint.Dark() e .Light() in System.Windows.Forms.

+3

brillante. perché non fa parte dello spazio dei nomi "Colori"? – itsho

+0

Bello. Si noti che il valore 'percOfLightLight' (secondo argomento del metodo e che in realtà è il suo nome) dovrebbe essere un float nell'intervallo da 0 a 1. Altri valori sono accettati, ma il comportamento non sarà quello desiderato. Esempio di codice per ottenere un colore più chiaro: 'Colore lighterColor = ControlPaint.Light (originalColor, 1.0f);' – Jinlye

0

Questo website note che è possibile utilizzare la classe ControlPaint all'interno dello spazio dei nomi System.Windows.Forms BCL C#.

44

In XNA there is the Color.Lerp static method questo fa la differenza tra due colori.

Lerp è un'operazione matematica tra due float che modifica il valore del primo per un rapporto della differenza tra di essi.

Ecco un metodo di estensione per farlo ad un float:

public static float Lerp(this float start, float end, float amount) 
{ 
    float difference = end - start; 
    float adjusted = difference * amount; 
    return start + adjusted; 
} 

Allora una semplice operazione lerp tra due colori utilizzando RGB sarebbe:

public static Color Lerp(this Color colour, Color to, float amount) 
{ 
    // start colours as lerp-able floats 
    float sr = colour.R, sg = colour.G, sb = colour.B; 

    // end colours as lerp-able floats 
    float er = to.R, eg = to.G, eb = to.B; 

    // lerp the colours to get the difference 
    byte r = (byte) sr.Lerp(er, amount), 
     g = (byte) sg.Lerp(eg, amount), 
     b = (byte) sb.Lerp(eb, amount); 

    // return the new colour 
    return Color.FromArgb(r, g, b); 
} 

Un esempio di applicazione di questo sarebbe qualcosa come:

// make red 50% lighter: 
Color.Red.Lerp(Color.White, 0.5f); 

// make red 75% darker: 
Color.Red.Lerp(Color.Black, 0.75f); 

// make white 10% bluer: 
Color.White.Lerp(Color.Blue, 0.1f); 
+0

+1 great answer thx. Ti fa impazzire a dover digitare Colore invece del colore nelle librerie .NET? :) –

+9

@ScottSilvi Ora ci sono abituato - non è così male in C# compilato, ma ho passato anni a cercare di capire cosa c'è che non va con un codice HTML/CSS/JS perché ho scritto correttamente il centro o il colore : S – Keith

+0

sintassi dell'esempio mi ha confuso ma ora l'ho capito ... devo solo riorganizzarlo suppongo che – ycomp

Problemi correlati