Znalezienie „równoważnego” koloru z kryciem


92

Powiedzmy, że mam tło w kolorze z „wstążką” w innym jednolitym kolorze. Teraz chcę, aby wstążka była częściowo przezroczysta, aby umożliwić przenikanie niektórych szczegółów, ale nadal utrzymywać wstążkę w „tym samym kolorze” na tle.

Czy jest sposób (łatwo) określić, dla danego krycia / alfa <100% koloru wstążki, jakie wartości RGB powinna być identyczna z jej kolorem ze 100% kryciem na tle?

Oto zdjęcie. Tło jest rgb(72, 28, 97), wstążka rgb(45, 34, 70). Chcę mieć rgba(r, g, b, a)na wstążce, aby wyglądała identycznie jak ten jednolity kolor.

wprowadź opis obrazu tutaj


1
Bardzo podobne pytanie można znaleźć tutaj: stackoverflow.com/questions/6672374/convert-rgb-rgba, ale kluczowa różnica polega na tym, że to pytanie określa podstawowy kolor bieli, podczas gdy to jest arbitralne.
BoltClock

Odpowiedzi:


129

Mieszanie kolorów to tylko liniowa interpolacja na kanał, prawda? Więc matematyka jest dość prosta. Jeśli masz RGBA1 nad RGB2, efektywnym efektem wizualnym RGB3 będzie:

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

… Gdzie kanał alfa wynosi od 0,0 do 1,0.

Kontrola poczytalności: jeśli alfa wynosi 0, czy RGB3 to to samo co RGB2? Tak. Jeśli alfa wynosi 1, to czy RGB3 to to samo co RGB1? Tak.

Jeśli zablokowałeś tylko kolor tła i kolor końcowy, istnieje duża liczba kolorów RGBA (nieskończona, w przestrzeni zmiennoprzecinkowej), które mogą spełnić wymagania. Musisz więc wybrać kolor paska lub żądany poziom krycia i sprawdzić wartość drugiego.

Wybór koloru na podstawie alfa

Jeśli znasz RGB3 (ostateczny pożądany kolor), RGB2 (kolor tła) i A1 (ile chcesz krycia) i szukasz tylko RGB1, możemy ponownie ułożyć równania w ten sposób:

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

Istnieje kilka kombinacji kolorów, które są teoretycznie możliwe, ale niemożliwe, biorąc pod uwagę standardowy zakres RGBA. Na przykład, jeśli tło jest czysto czarne, pożądany postrzegany kolor to czysta biel, a pożądana wartość alfa wynosi 1%, wtedy potrzebujesz:

r1 = g1 = b1 = 255/0.01 = 25500

… Superjasna biel 100 razy jaśniejsza niż wszystkie dostępne.

Wybór alfy na podstawie kolorów

Jeśli znasz RGB3 (ostateczny pożądany kolor), RGB2 (kolor tła) i RGB1 (kolor, który chcesz zmienić krycie), i szukasz tylko A1, możemy ponownie zaaranżować równania w ten sposób:

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

Jeśli dają one różne wartości, nie możesz dopasować ich dokładnie, ale możesz uśrednić alfy, aby zbliżyć się jak najbliżej. Na przykład nie ma na świecie przezroczystości, która pozwoliłaby umieścić zielony na czerwonym, aby uzyskać niebieski.


Nie są r1, g1i b1też nie wiadomo?
Eric

@Eric Nie jestem pewien. Zredagowałem odpowiedź na wypadek, gdyby był to poziom alfa, który jest znany, a kolory, które nie.
Phrogz

Uwaga, użyłem twoich pierwszych trzech formuł w Photoshopie, aby znaleźć kolor przy 0,8 alfa, gdy moim jedynym innym kolorem odniesienia był biały ... Musiałem użyć 1 + (1 - a) lub 1,2, aby znaleźć właściwy kolor ...
John William Domingo

1
@Phrogz Używam twoich równań „Wybierz kolor na podstawie alfa” i otrzymuję liczbę ujemną (-31) dla kanału czerwonego. Kiedy używam ujemnej wartości jako czerwonej wartości, otrzymuję taki sam wynik, jak gdybym użył 0 jako wartości czerwonej. Czy istnieje sposób na przekształcenie tego negatywu w coś użytecznego? Masz jakąś wskazówkę, co się tutaj dzieje?
Nocturno,

Może moje obliczenia są wyłączone, ale ta formuła daje nieoczekiwany wynik, gdy RGB3 = # 163920, RGB2 = #FFFFFF i A1 = 0,92; obliczone RGB1 = rgb (2, 40, 13), ale rgba (2, 40, 13, 0,92) = # 15381F, a nie # 163920.
2016

12

Zrobiłem MNIEJ mixinów, używając odpowiedzi Phrogza. wprowadzasz:

  1. jak powinien wyglądać kolor
  2. z pewną alfą
  3. na danym tle (domyślnie białe)

Oto kod:

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

}

Sposób użycia:

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

Oczywiście nie działa w przypadku niemożliwych kombinacji (jak wspomniał Phrogz), co oznacza, że ​​obsługiwane są tylko łagodne poziomy przezroczystości. Zobacz, jak sobie z tym poradzisz.


1
@mixin bg_alpha_calc ($ pożądany_kolor, $ pożądany_alpha, $ kolor_tła: biały) {$ r3: czerwony ($ pożądany_kolor); $ g3: zielony ($ pożądany_kolor); $ b3: niebieski ($ pożądany_kolor); $ r2: czerwony ($ kolor_tła); $ g2: zielony ($ kolor_tła); $ b2: niebieski ($ kolor_tła); // r1 = (r3 - r2 + r2 * a1) / a1 $ r1: ($ r3 - $ r2 + ($ r2 * $ pożądane_alfa)) / $ pożądane_alpha; $ g1: ($ g3 - $ g2 + ($ g2 * $ pożądane_alfa)) / $ pożądane_alfa; $ b1: ($ b3 - $ b2 + ($ b2 * $ pożądane_alfa)) / $ pożądane_alfa; background-color: $ pożądany_kolor; kolor tła: rgba ($ r1, $ g1, $ b1, $ pożądane_alpha); }
metaColin

2
Zaadoptowałem i stworzyłem mix w wersji SCSS. Znajdź demo i kod tutaj: codepen.io/Grienauer/pen/Grogdx
Grienauer

@Grienauer Zrobiłem dokładnie to samo, nie zdawałem sobie sprawy, że już to udostępniłeś! Jedyną różnicą jest to, że domyślnie
ustawiłem

7

Dzięki Phrogz „s i ephemer ” s wielkie odpowiedzi, o to, że funkcja SASS automagicznie oblicza najlepszy odpowiednik koloru RGBA.

Nazywasz to żądanym kolorem i istniejącym tłem, a on obliczy najlepszy (czyli najbardziej przezroczysty) odpowiednik koloru RGBA, który daje pożądany wynik w zakresie ± 1/256 każdego komponentu RGB (z powodu błędów zaokrąglenia):

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

Właśnie przetestowałem go z wieloma kombinacjami (wszystkie motywy Bootswatch) i działa to nie lada gratka, zarówno w przypadku ciemności na świetle, jak i światła na ciemności.

PS: Jeśli potrzebujesz dokładności większej niż ± 1/256 w wynikowym kolorze, musisz wiedzieć, jakiego rodzaju algorytmy zaokrąglania stosują przeglądarki podczas mieszania kolorów rgba (nie wiem, czy to jest standardowe, czy nie) i dodać odpowiedni stan istniejący @while, tak aby wzrastał $alphaaż do osiągnięcia pożądanej precyzji.


2
FYI, ta funkcja istnieje w Stylus jako transparentify(): stylus-lang.com/docs/bifs.html#transparentifytop-bottom-alpha ... którą odkryłem po ręcznym przeniesieniu tego do
Stylusa

6

Z odpowiedzi @Phrogz:

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

Więc:

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

Więc:

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

Uwaga Można wybrać dowolną wartość a1, a to znajdzie odpowiednie wartości r1, g1oraz b1wymagane. Na przykład wybranie alfa 1 oznacza, że ​​potrzebujesz RGB1 = RGB3, ale wybranie alfa 0 nie daje żadnego rozwiązania (oczywiście).


1

Najbardziej praktyczne rozwiązanie, jakie do tej pory znalazłem: po prostu zmierz wynikowy kolor za pomocą narzędzia do wybierania kolorów, a następnie użyj zmierzonego koloru do nałożenia. Ta metoda zapewnia idealne dopasowanie kolorów.

Próbowałem używać różnych miksów, ale z powodu błędu zaokrąglania nadal byłem w stanie zobaczyć różnicę gołym okiem


1
OP prawdopodobnie chciał sposób na dynamiczne określenie, ale nie zostało to wyraźnie określone, a twoja odpowiedź jest dobrym hackem dla statycznych wyborów kolorów / alfa.
Erik Knowles

0

Aby rozwinąć odpowiedź @ Tobia i umożliwić określenie krycia bardziej jak 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);
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.