Convertir RVB en RGBA sur blanc

J'ai une couleur hexadécimale, par exemple #F4F8FB (ou rgb(244, 248, 251)) que je veux convertir en une couleur aussi transparente que possible RGBA (lorsqu'elle est affichée sur le blanc). Un sens? Je cherche un algorithme, ou au moins une idée d'un algorithme pour savoir comment 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)

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)' 
    }
189
demandé sur Mark Kahn 2011-07-13 03:20:57

7 réponses

Prenez le composant de couleur le plus bas et convertissez-le en une valeur alpha. Ensuite, mettez à l'échelle les composants de couleur en soustrayant le plus bas et en 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

Donc, rgb(152, 177, 202) s'affiche comme rgba(0, 62, 123, .404).

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

181
répondu Guffa 2011-07-13 10:34:40

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 mathématiques 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 sera le facteur limitant dans le problème, donc liez ceci à m:

m = min(r, g, b)

Définir le valeur de sortie correspondante, m', à zéro, comme nous voulons maximiser la transparence:

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

Donc, en javascript (traduction 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 A ' est opacité ici. Il est trivial de le changer en transparence-il suffit de supprimer le "1 -" de la formule pour a'. Anothing chose à noter est que cela ne semble pas produire des résultats exacts - il a dit que l'opacité était 0.498 pour l'exemple que vous avez donné ci-dessus (128, 128, 255). Cependant, ce n'est très proche.

22
répondu gereeter 2011-07-13 07:15:30

Je voudrais regarder la conversion RVBHSL. C'est-à-dire luminosité = = quantité de blanc = = Quantité de transparence.

Pour votre exemple rgb( 128, 128, 255 ), nous devons d'abord décaler les valeurs RVB à 0 par montant maximum, c'est - à-dire à rgb( 0, 0, 128 ) - ce serait notre couleur avec le moins de blanc possible. Et après cela, en utilisant la formule pour la luminance, nous calculons la quantité de blanc que nous devons ajouter à notre couleur sombre pour obtenir la 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 c'est logique. :)

6
répondu lxa 2011-07-12 23:44:26

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
    );
}
4
répondu Stefan 2016-02-12 16:14:29

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

, Fondamentalement, vous disposez de trois numéros x, y, z et vous êtes à la recherche de trois nouveaux numéros x', y', z' et un multiplicateur a dans l'intervalle [0,1] telle 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 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. En valeurs réelles, cela a infiniment de solutions, il suffit de brancher n'importe quel nombre réel a, mais le problème est de trouver un nombre pour lequel l'erreur de discrétisation est minime.

2
répondu Kerrek SB 2011-07-13 07:16:52

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
répondu trutheality 2011-07-13 23:42:43

La réponse supérieure n'a pas fonctionné pour moi avec des composants de couleur basse. Par exemple, il ne calcule pas l'alpha correct si la couleur est #80000. Techniquement, il devrait en faire #ff0000 avec alpha 0.5. Pour résoudre ce problème, vous devez utiliser la conversion RGB -> HSL -> RGBA. C'est un pseudo code pour obtenir les valeurs correctes:

//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" contiendra la valeur de la nouvelle couleur ajustée et utilisera la variable "alpha" pour contrôler la transparence.

-1
répondu Arvydas Juskevicius 2014-10-08 16:05:33