web-dev-qa-db-fra.com

Conversion de RVB en RGBA sur blanc

J'ai une couleur hexagonale, par exemple #F4F8FB (Ou rgb(244, 248, 251)) que je souhaite convertir en une couleur aussi transparente que possible rgba (lorsqu'elle est affichée sur blanc). Avoir un sens? Je cherche un algorithme, ou au moins une idée d'un algorithme pour le faire.

Par exemple:

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

Des idées?


Solution FYI basée sur la réponse de 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)' 
    }
194
Mark Kahn

Prenez la composante de couleur la plus basse et convertissez-la en une valeur alpha. Puis redimensionnez les composantes de couleur en soustrayant la plus basse et en la divisant par la valeur alpha.

Exemple:

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

Ainsi, rgb(152, 177, 202) s'affiche sous la forme rgba(0, 62, 123, .404).

J'ai vérifié dans Photoshop que les couleurs correspondent parfaitement.

183
Guffa

Soit r, g et b les valeurs d'entrée et r ', g', b 'et a' les valeurs de sortie, toutes mises à l'échelle (pour l'instant, car cela rend les maths plus jolies) entre 1 et 0. Ensuite, par la formule pour superposer les couleurs:

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

Les termes 1 - a 'représentent la contribution de fond et les autres termes représentent le premier plan. Faites de l'algèbre:

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

Intuitivement, il semble que la valeur de couleur minimale soit le facteur limitant dans le problème, lions donc ceci à m:

m = min(r, g, b)

Définissez la valeur de sortie correspondante, m ', sur zéro, afin d'optimiser la transparence:

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

Donc, en javascript (traduisant de 1 à 255 en cours de route):

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

Notez que je suppose que 'est l'opacité ici. Il est trivial de le changer en transparence - supprimez simplement le "1 -" de la formule pour un '. Une chose à noter est que cela ne semble pas produire de résultats exacts - il est dit que l'opacité était de 0,498 pour l'exemple que vous avez donné ci-dessus (128, 128, 255). Cependant, c'est extrêmement proche.

23
gereeter

Je regarderais à la conversion RVB <-> HSL. C'est à dire. luminosité == quantité de blanc == quantité de transparence.

Pour votre exemple rgb( 128, 128, 255 ), nous devons commencer par décaler les valeurs RVB vers 0, C’est-à-dire vers rgb( 0, 0, 128 ) - ce serait notre couleur avec aussi peu de blanc que possible. Et après cela, en utilisant une formule pour la luminance, nous calculons la quantité de blanc que nous devons ajouter à notre couleur sombre pour obtenir une couleur originale - ce serait notre alpha:

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;

J'espère que cela a du sens. :)

6
lxa

Pour ceux d'entre vous qui utilisent SASS/SCSS, j'ai écrit une petite fonction SCSS afin que vous puissiez facilement utiliser l'algorithme décrit par @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
    );
}
5
Stefan

Je ne fais que décrire une idée pour l'algorithme, pas de solution complète:

En gros, vous avez trois nombres x, y, z et vous recherchez trois nouveaux nombres x', y', z' et un multiplicateur a dans l'intervalle [0,1] tel que:

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

Ceci est écrit en unités où les canaux prennent également des valeurs comprises dans la plage [0,1]. Dans les valeurs discrètes 8 bits, ce serait quelque chose comme ceci:

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

De plus, vous voulez la plus grande valeur possible a. Vous pouvez résoudre:

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

Etc. Dans les valeurs réelles, il existe une infinité de solutions, il suffit de connecter n'importe quel nombre réel a, mais le problème est de trouver un nombre pour lequel l'erreur de discrétisation est minimale.

2
Kerrek SB

Cela devrait le faire:

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