Trovare il colore "equivalente" con l'opacità


92

Supponiamo che io abbia un colore di sfondo con un "nastro" che lo attraversa in un altro colore solido. Ora, voglio che il nastro sia parzialmente trasparente per lasciare che alcuni dettagli si sfumino, ma mantenga comunque lo "stesso colore" sullo sfondo.

C'è un modo per determinare (facilmente), per una data opacità / alfa <100% del colore del nastro, quali valori RGB dovrebbe avere per essere identici al suo colore con il 100% di opacità sullo sfondo?

Ecco una foto. Lo sfondo è rgb(72, 28, 97), nastro rgb(45, 34, 70). Voglio un rgba(r, g, b, a)per il nastro in modo che appaia identico a questo colore solido.

inserisci qui la descrizione dell'immagine


1
Una domanda molto simile può essere trovata qui: stackoverflow.com/questions/6672374/convert-rgb-rgba ma la differenza fondamentale è che quella domanda specifica un colore di base bianco, mentre questo è arbitrario.
BoltClock

Risposte:


129

La fusione dei colori è solo un'interpolazione lineare per canale, giusto? Quindi la matematica è piuttosto semplice. Se hai RGBA1 su RGB2, il risultato visivo effettivo RGB3 sarà:

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

... dove il canale alfa è compreso tra 0,0 e 1,0.

Controllo di integrità: se l'alfa è 0, RGB3 è uguale a RGB2? Sì. Se l'alfa è 1, RGB3 è uguale a RGB1? Sì.

Se hai bloccato solo il colore di sfondo e il colore finale, ci sono un gran numero di colori RGBA (infiniti, nello spazio in virgola mobile) che potrebbero soddisfare i requisiti. Quindi devi scegliere il colore della barra o il livello di opacità che desideri e scoprire il valore dell'altro.

Scegliere il colore in base all'alfa

Se conosci RGB3 (il colore finale desiderato), RGB2 (il colore di sfondo) e A1 (quanta opacità vuoi) e stai solo cercando RGB1, allora possiamo riorganizzare le equazioni in questo modo:

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

Ci sono alcune combinazioni di colori che sono teoricamente possibili, ma impossibili data la gamma RGBA standard. Ad esempio, se lo sfondo è nero puro, il colore percepito desiderato è bianco puro e l'alfa desiderato è 1%, allora avresti bisogno di:

r1 = g1 = b1 = 255/0.01 = 25500

... un bianco super luminoso 100 volte più luminoso di qualsiasi altro disponibile.

Scegliere l'alfa in base ai colori

Se conosci RGB3 (il colore finale desiderato), RGB2 (il colore di sfondo) e RGB1 (il colore di cui vuoi variare l'opacità) e stai solo cercando A1, allora possiamo riorganizzare il equazioni così:

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

Se questi danno valori diversi, non puoi farlo corrispondere esattamente, ma puoi fare la media degli alfa per avvicinarti il ​​più possibile. Ad esempio, non c'è opacità al mondo che ti consenta di mettere il verde sul rosso per ottenere il blu.


Non sono r1, g1e b1anche sconosciuti?
Eric

@ Eric non sono sicuro. Ho modificato la risposta nel caso in cui sia il livello alfa che è noto e i colori che non lo sono.
Phrogz

Attenzione, ho usato le tue prime tre formule in Photoshop per trovare quale sarebbe un colore a 0.8 alpha quando il mio unico altro colore di riferimento era il bianco ... ho dovuto usare 1 + (1 - a) o 1.2 per trovare il colore giusto ...
John William Domingo

1
@Phrogz Sto usando le tue equazioni "Scegli il colore in base all'alfa" e ottengo un numero negativo (-31) per il canale rosso. Quando uso il negativo come valore del rosso, ottengo lo stesso risultato come se avessi usato 0 come valore del rosso. C'è un modo per convertire questo negativo in qualcosa di utilizzabile? Qualche indizio su cosa sta succedendo qui?
Nocturno

Forse i miei calcoli sono disattivati, ma questa formula produce risultati imprevisti quando RGB3 = # 163920, RGB2 = #FFFFFF e A1 = 0.92; RGB1 calcolato = rgb (2, 40, 13), ma rgba (2, 40, 13, 0.92) = # 15381F, non # 163920.
thdoan

12

ho fatto MENO mixin usando la risposta di Phrogz. inserisci:

  1. come dovrebbe apparire il colore
  2. con un certo alfa
  3. su un determinato sfondo (l'impostazione predefinita è bianca)

Ecco il codice:

.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);

}

Utilizzo in questo modo:

@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);
}

Ovviamente non funziona per combinazioni impossibili (come menzionato da Phrogz), ciò significa che sono supportati solo livelli di trasparenza lievi. Guarda come te la cavi.


1
@mixin bg_alpha_calc ($ desiderato_colour, $ desiderato_alpha, $ background_colour: bianco) {$ r3: rosso ($ desiderato_colour); $ g3: verde ($ colore_desiderato); $ b3: blu ($ colore_desiderato); $ r2: rosso ($ background_colour); $ g2: verde ($ background_colour); $ b2: blu ($ background_colour); // r1 = (r3 - r2 + r2 * a1) / a1 $ r1: ($ r3 - $ r2 + ($ r2 * $ desiderato_alfa)) / $ desiderato_alfa; $ g1: ($ g3 - $ g2 + ($ g2 * $ desiderato_alfa)) / $ desiderato_alfa; $ b1: ($ b3 - $ b2 + ($ b2 * $ desiderato_alfa)) / $ desiderato_alfa; colore di sfondo: $ desiderato_colore; colore di sfondo: rgba ($ r1, $ g1, $ b1, $ desiderato_alpha); }
metaColin

2
Ho adottato e realizzato un mixin di versione SCSS. Trova la demo e il codice qui: codepen.io/Grienauer/pen/Grogdx
Grienauer

@Grienauer Ho fatto lo stesso, non mi rendevo conto che l'hai già condiviso! La mia unica differenza è che ho impostato il colore di sfondo come
predefinito

7

Grazie alla Phrogz 's e Ephemer ' s grandi risposte, qui è una funzione SASS che automagicamente calcola il colore migliore RGBA equivalente.

Lo chiami con il colore desiderato e lo sfondo esistente e calcolerà il colore RGBA equivalente migliore (ovvero il più trasparente) che fornisce il risultato desiderato entro ± 1/256 di ciascun componente RGB (a causa di errori di arrotondamento):

@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);
}

L'ho appena testato con una serie di combinazioni (tutti i temi di Bootswatch) e funziona a meraviglia, sia per i risultati scuro su chiaro che chiaro su scuro.

PS: se hai bisogno di una precisione migliore di ± 1/256 nel colore risultante, dovrai sapere quale tipo di algoritmo di arrotondamento si applica ai browser quando si mescolano i colori rgba (non so se è standardizzato o meno) e aggiungi un condizione all'esistente @while, in modo che continui ad aumentare $alphafino a raggiungere la precisione desiderata.


2
Cordiali saluti, questa funzione esiste in Stylus come transparentify(): stylus-lang.com/docs/bifs.html#transparentifytop-bottom-alpha ... che ho scoperto dopo
averlo portato

6

Dalla risposta di @Phrogz:

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

Così:

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

Così:

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

Nota È possibile scegliere qualsiasi valore a1, e questo sarà trovare i valori corrispondenti r1, g1e b1richieste. Ad esempio, scegliere un alfa di 1 ti dice che hai bisogno di RGB1 = RGB3, ma scegliere un alfa di 0 non fornisce alcuna soluzione (ovviamente).


1

La soluzione più pratica che ho trovato finora: basta misurare il colore risultante con uno strumento di selezione dei colori e quindi utilizzare il colore misurato per la sovrapposizione. Questo metodo offre una perfetta corrispondenza dei colori.

Ho provato a utilizzare diversi mixin ma a causa di un errore di arrotondamento, sono stato comunque in grado di vedere la differenza ad occhio nudo


1
L'OP probabilmente voleva un modo per effettuare la determinazione in modo dinamico, ma non è stato specificato in modo specifico, e la tua risposta fornisce un buon trucco per le selezioni statiche di colore / alfa.
Erik Knowles,

0

Per espandere la risposta di @ Tobia e consentire di specificare l'opacità più simile a 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);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.