207 votes

Convertir RGB 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 rgba aussi transparente que possible (lorsqu'affichée sur du blanc). Vous me suivez ? Je cherche un algorithme, ou au moins une idée d'algorithme pour le faire.

Par exemple :

rgb( 128, 128, 255 ) --> rgba(   0,   0, 255,  .5 )
rgb( 152, 177, 202 ) --> rgba(  50, 100, 150,  .5 ) // peut être amélioré (alpha plus bas)

Des idées ?


Solution 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)' 
    }

0 votes

Intéressant! Vous voulez toujours qu'il soit visible, n'est-ce pas, pas complètement transparent?

6 votes

Question intéressante! Il y a une question exactement opposée sur stackoverflow.com/questions/2049230/convert-rgba-color-to-rgb, cela pourrait aider

0 votes

@Mrchief - Oui, je veux que la couleur reste la même lorsqu'elle est affichée sur du blanc, mais soit aussi transparente que possible.

194voto

Guffa Points 308133

Prenez le composant de couleur le plus bas, et convertissez-le en une valeur alpha. Ensuite, mettez à l'échelle les composantes de couleur en soustrayant le plus bas, et en divisant par la valeur alpha.

Exemple:

152 se convertit en une valeur alpha de (255 - 152) / 255 ~ 0.404

152 se met à l'échelle en utilisant (152 - 152) / 0.404 = 0
177 se met à l'échelle en utilisant (177 - 152) / 0.404 ~ 62
202 se met à l'échelle en utilisant (202 - 152) / 0.404 ~ 123

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

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

1 votes

Merci! Je faisais quelque chose de similaire (par exemple, obtenir .404) mais je n'arrivais pas tout à fait à faire fonctionner les chiffres.

3 votes

FYI, solution finale postée en fonction de votre réponse dans la question

2 votes

@templatetypedef: Convertir le composant le plus bas en alpha revient à mettre à l'échelle de la plage 0..255 à 0..1, et à l'inverser. Utiliser 1.0 - 152 / 255 fonctionnerait également. Convertir les composants de couleur revient simplement à mettre à l'échelle de n..255 à 0..255n est le composant le plus bas.

24voto

gereeter Points 2906

Laissez r, g et b être les valeurs d'entrée et r', g', b' et a' être 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 des 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 l'arrière-plan, et les autres termes représentent le premier plan. Faites quelques calculs :

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 attachez cela à m :

m = min(r, g, b)

Définissez la valeur de sortie correspondante, m', à zéro, car 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];
}

Remarquez que je suppose que a' est l'opacité ici. Il est trivial de le changer en transparence - il suffit de supprimer le "1 -" de la formule pour a'. Une autre chose à noter est que cela ne semble pas produire des résultats exacts - il a 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.

0 votes

Si vous distribuez le 255 multiplié dans votre équation, vous obtenez le bon résultat - [255 * (r/255 - 1) / a + 1 * 255, ...] == [(255*r/255 - 255 * 1) / a + 255, ...] == [(r - 255) / a + 255, ...]

6voto

lxa Points 1416

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

Pour votre exemple rgb( 128, 128, 255 ), nous devons d'abord décaler les valeurs RGB à 0 au 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 d'origine - 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. :)

3voto

Kerrek SB Points 194696

Je décris simplement une idée pour l'algorithme, pas de solution complète :

Essentiellement, vous avez trois nombres x, y, z et vous recherchez trois nouveaux nombres x', y', z' et un multiplicateur a dans la plage [0,1] tels 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]. En valeurs discrètes sur 8 bits, ça ressemblerait à 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 pour a. Vous pouvez résoudre :

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

Etc. En valeurs réelles, cela a un nombre infini de solutions, il suffit de saisir n'importe quel nombre réel pour a, mais le problème est de trouver un nombre pour lequel l'erreur de discrétisation est minimale.

0voto

trutheality Points 13261

Cela devrait fonctionner :

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

0 votes

Je viens juste de remarquer que j'avais une erreur dans le calcul de l'alpha (corrigée maintenant). Donc cela peut aussi y avoir joué un rôle.

0 votes

Il reste toujours un problème introduit par votre y et (y-x). Le 255 / (y-x) force incorrectement le plus grand nombre à 255, donc vous vous retrouveriez toujours avec un seul 0, un seul 255 et ensuite un autre nombre: 0, 22, 255, 255, 0, 55, etc...

0 votes

Je vois, donc cela n'autorisera pas les couleurs plus sombres... Je devrais juste le faire /a et ensuite cela correspond à la réponse correcte.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X