2012-06-20 25 views
37

Esiste una procedura ottimale su come hash una stringa arbitraria in un valore di colore RGB? O per essere più generale: a 3 byte.Hash stringa in colore RGB

Stai chiedendo: quando mai avrò bisogno di questo? Non ha importanza per me, ma immagina quei grafici a tubo su qualsiasi GitHub network page. Ci si può vedere qualcosa di simile:

git branches

Dove ogni linea colorata indica un ramo git distinta. L'approccio low-tech per colorare questi rami sarebbe un CLUT (tabella di ricerca del colore). La versione più sofisticata sarebbe:

$branchColor = hashStringToColor(concat($username,$branchname)); 

Perché si desidera un colore statico ogni volta che si vede la rappresentazione di rami. E per i punti bonus: come garantisci una distribuzione uniforme dei colori di quella funzione hash?

Quindi la risposta alla mia domanda si riduce all'implementazione di hashStringToColor().

risposta

26

Una buona funzione di hash fornirà una distribuzione quasi uniforme sullo spazio dei tasti. Ciò riduce la domanda su come convertire un numero casuale a 32 bit in uno spazio RGB a 3 byte. Non vedo nulla di sbagliato nel prendere solo i 3 byte bassi.

int hash = string.getHashCode(); 
int r = (hash & 0xFF0000) >> 16; 
int g = (hash & 0x00FF00) >> 8; 
int b = hash & 0x0000FF; 
+0

Ha funzionato alla grande, grazie. – clayzermk1

+9

Anche se si desidera garantire colori leggibili (ad esempio, garantire un contrasto e una saturazione sufficientemente elevati), si dovrà fare un po 'più di lavoro. Potrebbe essere più facile lavorare in HSV o LAB e convertire in RGB. – naught101

+0

Bella soluzione! –

2

Ad esempio, this is how Java calculates the hashcode of a string (riga 1494 e seguenti). Restituisce un int. È quindi possibile calcolare il modulo di quello int con 16,777,216 (2^24 = 3 byte) per ottenere un numero "RGB compatibile".

È un calcolo deterministico, quindi la stessa parola (o le stesse parole) avrà sempre lo stesso colore. La probabilità di collisione dell'hash (2 stringhe dello stesso colore) è piccola. Non sono sicuro della distribuzione dei colori, ma probabilmente è abbastanza casuale.

+0

Penso collisioni hash possono essere trascurate, dal momento che quando si verifica una collisione che non è tanto un problema fino a quando non c'è bisogno di vicini di casa i colori (come nell'esempio dato) per essere diverso. –

+1

La casualità della distribuzione dei colori potrebbe essere un problema estetico. Ci sono un sacco di colori "brutti", potrebbe essere un'idea pratica applicare una sorta di peso ai componenti per cercare di migliorare la bella: rapporto brutto. :) – Wug

19

Per tutti gli utenti Javascript là fuori, ho unito la risposta accettata da @ jeff-adottiva con la funzione di hash djb2 da erlycoder.

Il risultato per la domanda:

function djb2(str){ 
    var hash = 5381; 
    for (var i = 0; i < str.length; i++) { 
    hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */ 
    } 
    return hash; 
} 

function hashStringToColor(str) { 
    var hash = djb2(str); 
    var r = (hash & 0xFF0000) >> 16; 
    var g = (hash & 0x00FF00) >> 8; 
    var b = hash & 0x0000FF; 
    return "#" + ("0" + r.toString(16)).substr(-2) + ("0" + g.toString(16)).substr(-2) + ("0" + b.toString(16)).substr(-2); 
} 

UPDATE: Corretta la stringa di ritorno per tornare sempre un # 000000 formato stringa esadecimale sulla base di una modifica di @alexc (grazie!).

+3

Puoi anche formattare il colore in questo modo: ritorna "rgb (" + r + "," + g + "," + b + ")" –

+1

@StuGla: non riesco a ricordare se il formato esadecimale faceva parte del requisiti; leggendolo ora non sembra essere. Poiché la domanda è stata posta in modo generico, penso che l'autore fosse più interessato all'algoritmo di hash che al formato della stringa di colore. Tuttavia, se il contesto della domanda è CSS, il tuo sarebbe un modo molto più pulito per farlo. Grazie amico! – clayzermk1

+0

@StuGla: consente anche di aggiungere trasparenza. – MastaBaba

8

Ho provato tutte le soluzioni fornite da altri ma ho trovato che stringhe simili (string1 vs string2) producono colori che sono troppo simili per i miei gusti. Pertanto, ho costruito il mio influenzato dall'input e dalle idee degli altri.

Questo calcola il checksum MD5 della stringa e prende le prime 6 cifre esadecimali per definire il codice RGB a 24 bit.

La funzionalità MD5 è un open-source JQuery collegare La funzione JS è la seguente:.

function getRGB(str){ 
    var hash = $.md5(str); 
    var rgb = '#' + hash.substring(0,2) + hash.substring(2,4) + hash.substring(4,6); 
    return rgb; 
} 

Un collegamento in questo esempio funzionante inizia jsFiddle. Basta inserire una stringa nel campo di inserimento e premere Invio, e farlo più volte per confrontare i risultati.

+0

Puoi semplificare la riga 3 a: 'var rgb = '#' + hash.substring (0,6);' –

+0

* Ho provato tutte le soluzioni fornite da altri (...) * No, non l'hai :) come risposta di Jeff Foster descrive la famiglia con ** infinite ** molte soluzioni. La tua soluzione è un membro di questa famiglia, btw. –

Problemi correlati