Recherche d'une couleur «équivalente» avec opacité

92

Disons que j'ai une couleur d'arrière-plan avec un "ruban" qui passe dessus dans une autre couleur unie. Maintenant, je veux que le ruban soit partiellement transparent pour laisser certains détails se fondre, tout en gardant le ruban de la «même couleur» sur l'arrière-plan.

Existe-t-il un moyen de déterminer (facilement), pour une opacité / alpha donnée <100% de la couleur du ruban, quelles valeurs RVB il devrait avoir pour être identique à sa couleur avec une opacité de 100% sur l'arrière-plan?

Voici une image. Le fond est rgb(72, 28, 97), ruban rgb(45, 34, 70). Je veux un rgba(r, g, b, a)pour le ruban afin qu'il apparaisse identique à cette couleur unie.

entrez la description de l'image ici

Vicvicvic
la source
1
Une question très similaire peut être trouvée ici: stackoverflow.com/questions/6672374/convert-rgb-rgba mais la principale différence est que cette question spécifie une couleur de base de blanc, alors que celle-ci est arbitraire.
BoltClock

Réponses:

129

La fusion des couleurs n'est qu'une interpolation linéaire par canal, n'est-ce pas? Le calcul est donc assez simple. Si vous avez RGBA1 sur RGB2, le résultat visuel effectif RGB3 sera:

r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1

… Où le canal alpha est compris entre 0,0 et 1,0.

Vérification de l'intégrité: si l'alpha est 0, RGB3 est-il identique à RGB2? Oui. Si l'alpha est 1, RGB3 est-il identique à RGB1? Oui.

Si vous avez verrouillé uniquement la couleur d'arrière-plan et la couleur finale, il existe un grand nombre de couleurs RGBA (infinies, dans un espace à virgule flottante) qui pourraient satisfaire les exigences. Vous devez donc choisir soit la couleur de la barre, soit le niveau d'opacité souhaité, et découvrir la valeur de l'autre.

Choisir la couleur basée sur Alpha

Si vous connaissez RGB3 (la couleur finale souhaitée), RGB2 (la couleur d'arrière-plan) et A1 (combien d'opacité vous voulez), et que vous recherchez simplement RGB1, nous pouvons réorganiser les équations ainsi:

r1 = (r3 - r2 + r2*a1)/a1
g1 = (g3 - g2 + g2*a1)/a1
b1 = (b3 - b2 + b2*a1)/a1

Certaines combinaisons de couleurs sont théoriquement possibles, mais impossibles compte tenu de la plage RGBA standard. Par exemple, si l'arrière-plan est d'un noir pur, que la couleur perçue souhaitée est le blanc pur et que l'alpha souhaité est de 1%, vous aurez besoin de:

r1 = g1 = b1 = 255/0.01 = 25500

… Un blanc ultra-brillant 100 fois plus brillant que tout autre disponible.

Choisir l'alpha en fonction des couleurs

Si vous connaissez RGB3 (la couleur finale souhaitée), RGB2 (la couleur d'arrière-plan) et RGB1 (la couleur dont vous souhaitez faire varier l'opacité), et que vous recherchez simplement A1, nous pouvons réorganiser le équations ainsi:

a1 = (r3-r2) / (r1-r2)
a1 = (g3-g2) / (g1-g2)
a1 = (b3-b2) / (b1-b2)

Si ceux-ci donnent des valeurs différentes, vous ne pouvez pas le faire correspondre exactement, mais vous pouvez faire la moyenne des alphas pour vous rapprocher le plus possible. Par exemple, il n'y a aucune opacité dans le monde qui vous permettra de mettre du vert sur du rouge pour obtenir du bleu.

Phrogz
la source
Ne sont pas r1, g1et b1également inconnus?
Eric
@Eric Je ne suis pas certain. J'ai modifié la réponse au cas où ce serait le niveau alpha qui est connu et les couleurs qui ne le sont pas.
Phrogz
Attention, j'ai utilisé vos trois premières formules dans Photoshop pour trouver ce que serait une couleur à 0,8 alpha lorsque ma seule autre couleur de référence était le blanc ... J'ai dû utiliser 1 + (1 - a) ou 1,2 pour trouver le bonne couleur ...
John William Domingo
1
@Phrogz J'utilise vos équations «Choisissez la couleur en fonction de l'alpha» et j'obtiens un nombre négatif (-31) pour le canal rouge. Lorsque j'utilise le négatif comme valeur rouge, j'obtiens le même résultat que si j'avais utilisé 0 comme valeur rouge. Existe-t-il un moyen de convertir ce négatif en quelque chose utilisable? Un indice sur ce qui se passe ici?
Nocturno le
Peut-être que mes calculs sont désactivés, mais cette formule produit un résultat inattendu lorsque RGB3 = # 163920, RGB2 = #FFFFFF et A1 = 0.92; le RGB1 calculé = rgb (2, 40, 13), mais rgba (2, 40, 13, 0.92) = # 15381F, pas # 163920.
thdoan
12

J'ai fait un mixin MOINS en utilisant la réponse de Phrogz. vous entrez:

  1. à quoi devrait ressembler la couleur
  2. avec un certain alpha
  3. sur un fond donné (par défaut étant blanc)

Voici le code:

.bg_alpha_calc (@desired_colour, @desired_alpha, @background_colour: white) {
    @r3: red(@desired_colour);
    @g3: green(@desired_colour);
    @b3: blue(@desired_colour);

    @r2: red(@background_colour);
    @g2: green(@background_colour);
    @b2: blue(@background_colour);

    // r1 = (r3 - r2 + r2 * a1) / a1
    @r1: ( @r3 - @r2 + (@r2 * @desired_alpha) ) / @desired_alpha;
    @g1: ( @g3 - @g2 + (@g2 * @desired_alpha) ) / @desired_alpha;
    @b1: ( @b3 - @b2 + (@b2 * @desired_alpha) ) / @desired_alpha;

    background-color: @desired_colour;
    background-color: rgba(@r1, @g1, @b1, @desired_alpha);

}

Utilisation comme ceci:

@mycolour: #abc;
@another_colour: blue;
.box_overlay {
  // example:
  .bg_alpha_calc (@mycolour, 0.97, @another_colour);
  // or (for white bg) just:
  .bg_alpha_calc (@mycolour, 0.97);
}

Évidemment, cela ne fonctionne pas pour des combinaisons impossibles (comme mentionné par Phrogz), cela signifie que seuls des niveaux de transparence légers sont pris en charge. Voyez comment vous allez avec.

éphémère
la source
1
@mixin bg_alpha_calc ($ couleur_désirée, $ alpha_désiré, $ couleur_arrière-plan: blanc) {$ r3: rouge ($ couleur_souhaitée); $ g3: vert ($ couleur_désirée); $ b3: bleu ($ couleur_désirée); $ r2: rouge ($ couleur_arrière-plan); $ g2: vert ($ couleur_arrière-plan); $ b2: bleu ($ couleur_arrière-plan); // r1 = (r3 - r2 + r2 * a1) / a1 $ r1: ($ r3 - $ r2 + ($ r2 * $ désiré_alpha)) / $ désiré_alpha; $ g1: ($ g3 - $ g2 + ($ g2 * $ désiré_alpha)) / $ désiré_alpha; $ b1: ($ b3 - $ b2 + ($ b2 * $ désiré_alpha)) / $ désiré_alpha; couleur de fond: $ couleur_souhaitée; couleur de fond: rgba ($ r1, $ g1, $ b1, $ désiré_alpha); }
metaColin
2
J'ai adopté et réalisé un mixin version SCSS. Retrouvez la démo et le code ici: codepen.io/Grienauer/pen/Grogdx
Grienauer
@Grienauer J'ai fait exactement la même chose, je ne savais pas que tu l'avais déjà partagé! Ma seule différence est que j'ai défini par défaut la couleur d'arrière-plan en blanc
tehlivi
7

Merci à Phrogz 's et Ephemer grandes réponses de, voici une fonction SASS qui automagiquement calcule la meilleure couleur RGBA équivalent.

Vous l'appelez avec la couleur souhaitée et l'arrière-plan existant, et il calculera la meilleure couleur RVBA équivalente (c'est-à-dire la plus transparente) qui donne le résultat souhaité à ± 1/256 de chaque composant RVB (en raison d'erreurs d'arrondi):

@function alphaize($desired-color, $background-color) {

    $r1: red($background-color);
    $g1: green($background-color);
    $b1: blue($background-color);

    $r2: red($desired-color);
    $g2: green($desired-color);
    $b2: blue($desired-color);

    $alpha: 0;
    $r: -1;
    $g: -1;
    $b: -1;

    @while $alpha < 1 and ($r < 0 or $g < 0 or $b < 0
                           or $r > 255 or $g > 255 or $b > 255) {
        $alpha: $alpha + 1/256;
        $inv: 1 / $alpha;
        $r: $r2 * $inv + $r1 * (1 - $inv);
        $g: $g2 * $inv + $g1 * (1 - $inv);
        $b: $b2 * $inv + $b1 * (1 - $inv);
    }

    @return rgba($r, $g, $b, $alpha);
}

Je viens de le tester contre un certain nombre de combinaisons (tous les thèmes Bootswatch) et cela fonctionne un régal, à la fois pour les résultats sombre sur lumière et clair sur sombre.

PS: Si vous avez besoin d'une précision supérieure à ± 1/256 dans la couleur résultante, vous devrez savoir quel type d'algorithme d'arrondi les navigateurs appliquent lors du mélange de couleurs rgba (je ne sais pas si cela est normalisé ou non) et ajouter un condition à l'existant @while, de sorte qu'il continue d'augmenter $alphajusqu'à ce qu'il atteigne la précision souhaitée.

Tobie
la source
2
Pour info, cette fonction existe dans Stylus sous le nom transparentify(): stylus-lang.com/docs/bifs.html#transparentifytop-bottom-alpha ... que j'ai découvert après l'avoir porté manuellement sur Stylus ...
weotch
6

De la réponse de @Phrogz:

r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1

Donc:

r3 - r2 = (r1-r2)*a1
g3 - g2 = (g1-g2)*a1
b3 - b2 = (b1-b2)*a1

Donc:

r1 = (r3 - r2) / a1 + r2
g1 = (g3 - g2) / a1 + g2
b1 = (b3 - b2) / a1 + b2

Notez que vous pouvez choisir une valeur a1, et cela trouvera les valeurs de correspondants r1, g1et b1nécessaires. Par exemple, choisir un alpha de 1 vous indique que vous avez besoin de RGB1 = RGB3, mais choisir un alpha de 0 ne donne aucune solution (évidemment).

Eric
la source
1

La solution la plus pratique que j'ai trouvée jusqu'à présent: il suffit de mesurer la couleur résultante avec un outil de sélection de couleur, puis d'utiliser la couleur mesurée pour la superposition. Cette méthode donne une correspondance de couleur parfaite.

J'ai essayé d'utiliser différents mixins mais en raison d'une erreur d'arrondi, j'ai toujours pu voir la différence à l'œil nu

programme d’exécution
la source
1
L'OP voulait probablement un moyen de faire la détermination de manière dynamique, mais cela n'a pas été spécifiquement indiqué, et votre réponse donne un bon hack pour les sélections statiques de couleur / alpha.
Erik Knowles le
0

Pour développer la réponse de @ Tobia et permettre de spécifier l'opacité plus comme transparentify:

@function rgbaMorph($desired-color, $background-color: rgb(255,255,255), $desired-alpha: 0) {

    $r1: red($desired-color);
    $g1: green($desired-color);
    $b1: blue($desired-color);

    $r2: red($background-color);
    $g2: green($background-color);
    $b2: blue($background-color);

    $r: -1;
    $g: -1;
    $b: -1;

    @if ($desired-alpha != 0) {
        $r: ( $r1 - $r2 + ($r2 * $desired-alpha) ) / $desired-alpha;
        $g: ( $g1 - $g2 + ($g2 * $desired-alpha) ) / $desired-alpha;
        $b: ( $b1 - $b2 + ($b2 * $desired-alpha) ) / $desired-alpha;
    }

    @if (($desired-alpha == 0) or ($r < 0 or $g < 0 or $b < 0
                           or $r > 255 or $g > 255 or $b > 255)) {
        //if alpha not attainable, this will find lowest alpha that is

        $alpha: $desired-alpha;
        @while $alpha < 1 and ($r < 0 or $g < 0 or $b < 0
                           or $r > 255 or $g > 255 or $b > 255) {
            $alpha: $alpha + 1/256;
            $inv: 1 / $alpha;
            $r: $r1 * $inv + $r2 * (1 - $inv);
            $g: $g1 * $inv + $g2 * (1 - $inv);
            $b: $b1 * $inv + $b2 * (1 - $inv);
        }
        @debug "Color not attainable at opacity using alpha: " $alpha " instead of: " $desired-alpha;

        $desired-alpha: $alpha;
    }

    @return rgba($r, $g, $b, $desired-alpha);
}
phazei
la source