Converti RGB in RGBA su bianco

Ho un colore esadecimale, ad esempio #F4F8FB (o rgb(244, 248, 251) ) che voglio convertire in un colore rgba as-transparent-as-possible (quando visualizzato su bianco). Ha senso? Sto cercando un algoritmo, o almeno l’idea di un algoritmo su come farlo.

Per esempio:

 rgb( 128, 128, 255 ) --> rgba( 0, 0, 255, .5 ) rgb( 152, 177, 202 ) --> rgba( 50, 100, 150, .5 ) // can be better(lower alpha) 

Idee?


Soluzione FYI basata sulla risposta di Guffa:

 function RGBtoRGBA(r, g, b){ if((g == null) && (typeof r === 'string')){ var hex = r.replace(/^\s*#|\s*$/g, ''); if(hex.length === 3){ hex = hex.replace(/(.)/g, '$1$1'); } r = parseInt(hex.substr(0, 2), 16); g = parseInt(hex.substr(2, 2), 16); b = parseInt(hex.substr(4, 2), 16); } var min, a = (255 - (min = Math.min(r, g, b))) / 255; return { r : r = 0|(r - min) / a, g : g = 0|(g - min) / a, b : b = 0|(b - min) / a, a : a = (0|1000*a)/1000, rgba : 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')' }; } RGBtoRGBA(204, 153, 102) == RGBtoRGBA('#CC9966') == RGBtoRGBA('C96') == { r : 170, g : 85 , b : 0 , a : 0.6, rgba : 'rgba(170, 85, 0, 0.6)' } 

    Prendi il componente di colore più basso e convertilo in un valore alfa. Quindi ridimensiona i componenti del colore sottraendo il più basso e dividendo per il valore alfa.

    Esempio:

     152 converts to an alpha value of (255 - 152) / 255 ~ 0.404 152 scales using (152 - 152) / 0.404 = 0 177 scales using (177 - 152) / 0.404 ~ 62 202 scales using (202 - 152) / 0.404 ~ 123 

    Quindi, rgb(152, 177, 202) viene visualizzato come rgba(0, 62, 123, .404) .

    Ho verificato in Photoshop che i colors corrispondono perfettamente.

    Sia r, g e b i valori di input e r ‘, g’, b ‘e a’ siano i valori di uscita, tutti in scala (per ora, dato che rende la matematica più carina) tra 1 e 0. Quindi, per la formula per sovrapporre i colors:

     r = a' * r' + 1 - a' g = a' * g' + 1 - a' b = a' * b' + 1 - a' 

    I termini 1 – a ‘rappresentano il contributo dello sfondo e gli altri termini rappresentano il primo piano. Fai qualche algebra:

     r = a' * (r' - 1) + 1 r - 1 = a' * (r' - 1) (r - 1) / (r' - 1) = a' (r' - 1) / (r - 1) = 1 / a' r' - 1 = (r - 1) / a' r' = (r - 1) / a' + 1 

    Intuitivamente, sembra che il valore minimo del colore sia il fattore limitante del problema, quindi legalo a m:

     m = min(r, g, b) 

    Imposta il valore di uscita corrispondente, m ‘, su zero, poiché vogliamo massimizzare la trasparenza:

     0 = (m - 1) / a' + 1 -1 = (m - 1) / a' -a' = m - 1 a' = 1 - m 

    Quindi, in javascript (traducendo da 1 a 255 lungo la strada):

     function rgba(r, g, b) { var a = 1 - Math.min(r, Math.min(g, b)) / 255; return [255 + (r - 255) / a, 255 + (g - 255) / a, 255 + (b - 255) / a, a]; } 

    Si noti che sto assumendo che un ‘è opacità qui. È banale cambiarlo in trasparenza: basta rimuovere “1 -” dalla formula per un ‘. Notevole cosa da notare è che questo non sembra produrre risultati esatti – ha detto che l’opacità era 0,498 per l’esempio che hai dato sopra (128, 128, 255). Tuttavia, questo è estremamente vicino.

    Guarderei alla conversione RGB <-> HSL. Luminosità == quantità di bianco == quantità di trasparenza.

    Per il tuo esempio rgb( 128, 128, 255 ) , abbiamo bisogno di spostare i valori RGB a 0 prima per quantità massima, cioè a rgb( 0, 0, 128 ) – questo sarebbe il nostro colore con il minor numero ansible di bianchi. E dopo, usando la formula per la luminanza, calcoliamo la quantità di bianco che dobbiamo aggiungere al nostro colore scuro per ottenere il colore originale – sarebbe il nostro alfa:

     L = (MAX(R,G,B) + MIN(R,G,B))/2 L1 = (255 + 128) / 2 = 191.5 L2 = (128 + 0) /2 = 64 A = (191,5 - 64) / 255 = 0,5; 

    Spero che abbia un senso. 🙂

    Per quelli di voi che usano SASS / SCSS, ho scritto una piccola funzione SCSS in modo da poter usare facilmente l’algoritmo descritto da @Guffa

     @function transparentize-on-white($color) { $red: red($color); $green: green($color); $blue: blue($color); $lowestColorComponent: min($red, $green, $blue); $alpha: (255 - $lowestColorComponent) / 255; @return rgba( ($red - $lowestColorComponent) / $alpha, ($green - $lowestColorComponent) / $alpha, ($blue - $lowestColorComponent) / $alpha, $alpha ); } 

    Sto solo descrivendo un’idea per l’algoritmo, nessuna soluzione completa:

    Fondamentalmente, hai tre numeri x , y , z e stai cercando tre nuovi numeri x' , y' , z' e un moltiplicatore a nell’intervallo [0,1] tale che:

     x = a + (1 - a) x' y = a + (1 - a) y' z = a + (1 - a) z' 

    Questo è scritto in unità in cui i canali assumono anche valori nell’intervallo [0,1]. In valori discreti a 8 bit, sarebbe qualcosa del genere:

     x = 255 a + (1 - a) x' y = 255 a + (1 - a) y' z = 255 a + (1 - a) z' 

    Inoltre, vuoi il massimo valore ansible a . Puoi risolvere:

     a = (x - x')/(255 - x') x' = (x - 255 a)/(1 - a) 

    Ecc. In valori reali questo ha infinite soluzioni, basta inserire qualsiasi numero reale a , ma il problema è trovare un numero per il quale l’errore di discretizzazione sia minimo.

    Questo dovrebbe farlo:

     let x = min(r,g,b) a = 1 - x/255 # Correction 1 r,g,b = ( (r,g,b) - x ) / a # Correction 2 

    La risposta migliore non ha funzionato per me con componenti a basso colore. Ad esempio, non calcola l’alfa corretto se il colore è # 80000. Tecnicamente dovrebbe trasformarsi in # ff0000 con alpha 0.5. Per risolvere questo problema, devi utilizzare la conversione RGB -> HSL -> RGBA. Questo è uno pseudo codice per ottenere i valori corretti:

     //Convert RGB to HSL hsl = new HSL(rgb) //Use lightness as alpha alpha = hsl.Lightness //For #80000 lightness is 0.5, so we have to take this into account. //Lightness more than 0.5 converts to alpha 1 and below is a linear ratio if (alpha > 0.5) { alpha = 1; } else { alpha = alpha / 0.5; //We need to drop the lightness of the color to 0.5 to get the actual color //that needs to display. Alpha blending will take care of that. hsl.Lightness = 0.5; } newRgb = hsl.convertToRgb() 

    “newRgb” conterrà il valore del nuovo colore regolato e utilizzerà la variabile “alpha” per controllare la trasparenza.