Opaklıkla "eşdeğer" rengi bulma


92

Üzerinde başka bir düz renkte "şerit" geçen bir arka plan rengim olduğunu varsayalım. Şimdi, şeridin bazı ayrıntıların karışmasına izin vermek için kısmen şeffaf olmasını ama yine de şeridi arka planda "aynı renkte" tutmasını istiyorum.

Şerit renginin% 100'ünden küçük belirli bir opaklık / alfa için, arka plan üzerinde% 100 opaklıkla rengiyle aynı olması gereken RGB değerlerini belirlemenin (kolayca) bir yolu var mı?

İşte bir resim. Arka plan rgb(72, 28, 97), şerit rgb(45, 34, 70). rgba(r, g, b, a)Bu düz renkle aynı görünmesi için şerit için bir istiyorum .

görüntü açıklamasını buraya girin


1
Burada çok benzer bir soru bulunabilir: stackoverflow.com/questions/6672374/convert-rgb-rgba, ancak temel fark, bu sorunun isteğe bağlı olarak beyazın temel rengini belirtmesidir.
BoltClock

Yanıtlar:


129

Renk harmanlama, kanal başına yalnızca doğrusal bir enterpolasyondur, değil mi? Yani matematik oldukça basit. RGB2 üzerinden RGBA1'e sahipseniz, etkili görsel sonuç RGB3 şöyle olacaktır:

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

… Alfa kanalı 0,0 ile 1,0 arasında olduğunda.

Sağlamlık kontrolü: Alfa 0 ise, RGB3 RGB2 ile aynı mıdır? Evet. Alfa 1 ise, RGB3 RGB1 ile aynı mıdır? Evet.

Yalnızca arka plan rengini ve son rengi kilitlediyseniz, gereksinimleri karşılayabilecek çok sayıda RGBA rengi (kayan nokta alanında sonsuz) vardır. Yani çubuğun rengini veya istediğiniz opaklık seviyesini seçmeli ve diğerinin değerini bulmalısınız.

Alfaya Göre Renk Seçimi

RGB3 (istenen son renk), RGB2 (arka plan rengi) ve A1'i (ne kadar opaklık istediğinizi) biliyorsanız ve sadece RGB1'i arıyorsanız, denklemleri şu şekilde yeniden düzenleyebiliriz:

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

Teorik olarak mümkün olan, ancak standart RGBA aralığı göz önüne alındığında imkansız olan bazı renk kombinasyonları vardır. Örneğin, arka plan saf siyahsa, istenen algılanan renk saf beyazsa ve istenen alfa% 1 ise, şunlara ihtiyacınız olacaktır:

r1 = g1 = b1 = 255/0.01 = 25500

… Süper parlak beyaz, mevcut tüm modellerden 100 kat daha parlak.

Alfa'yı Renklere Göre Seçme

RGB3 (istenen son renk), RGB2 (arka plan rengi) ve RGB1'i (opaklığını değiştirmek istediğiniz renk) biliyorsanız ve sadece A1'i arıyorsanız, o zaman yeniden düzenleyebiliriz. dolayısıyla denklemler:

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

Bunlar farklı değerler verirse, tam olarak eşleşmesini sağlayamazsınız, ancak olabildiğince yakınlaşmak için alfaların ortalamasını alabilirsiniz. Örneğin, dünyada maviye dönüşmek için yeşili kırmızının üzerine koymanıza izin verecek hiçbir opaklık yoktur.


Değil misin r1, g1ve b1bilinmeyen ayrıca?
Eric

@Eric Emin değilim. Bilinen alfa seviyesi ve bilinmeyen renkler olması durumunda cevabı düzenledim.
Phrogz

Dikkat, Photoshop'taki ilk üç formülünüzü kullanarak diğer tek referans rengim beyazken 0,8 alfa rengin ne olacağını bulmak için kullandım ... 1 + (1 - a) veya doğru renk ...
John William Domingo

1
@Phrogz 'Alfaya Göre Renk Seç' denklemlerinizi kullanıyorum ve kırmızı kanal için negatif bir sayı (-31) alıyorum. Negatifi kırmızı değer olarak kullandığımda, kırmızı değer olarak 0 kullanmışım gibi aynı sonucu alıyorum. Bu negatifi kullanılabilir bir şeye dönüştürmenin bir yolu var mı? Burada neler olduğuna dair bir fikrin var mı?
Nocturno

Belki hesaplamalarım kapalı olabilir, ancak bu formül RGB3 = # 163920, RGB2 = #FFFFFF ve A1 = 0.92 olduğunda beklenmeyen sonuç üretir; hesaplanan RGB1 = rgb (2, 40, 13), ancak rgba (2, 40, 13, 0.92) = # 15381F, # 163920 değil.
thdoan

12

Phrogz'un cevabını kullanarak DAHA AZ mixin yaptım. giriyorsun:

  1. renk nasıl görünmeli
  2. belirli bir alfa ile
  3. belirli bir arka planda (varsayılan beyazdır)

İşte 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);

}

Bunun gibi kullanım:

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

Açıkçası imkansız kombinasyonlar için işe yaramıyor (Phrogz tarafından belirtildiği gibi), bu sadece hafif şeffaflık seviyelerinin desteklendiği anlamına geliyor. Nasıl gittiğini gör.


1
@mixin bg_alpha_calc ($ istenilen_renk, $ istenilen_alpha, $ arkaplan_renk: beyaz) {$ r3: kırmızı ($ istenilen_renk); $ g3: yeşil ($ istenen_renk); $ b3: mavi ($ istenen_renk); $ r2: kırmızı ($ arkaplan_renkli); $ g2: yeşil ($ arka plan_renk); $ b2: mavi ($ background_colour); // r1 = (r3 - r2 + r2 * a1) / a1 $ r1: ($ r3 - $ r2 + ($ r2 * $ istenilen_alpha)) / $ istenilen_alpha; $ g1: ($ g3 - $ g2 + ($ g2 * $ istenilen_alpha)) / $ istenilen_alpha; $ b1: ($ b3 - $ b2 + ($ b2 * $ istenilen_alpha)) / $ istenilen_alpha; arkaplan rengi: $ istenilen_renk; arkaplan rengi: rgba ($ r1, $ g1, $ b1, $ istenilen_alpha); }
metaColin

2
Bir SCSS versiyon karışımı benimsedim ve yaptım. Demoyu ve kodu burada bulabilirsiniz: codepen.io/Grienauer/pen/Grogdx
Grienauer

@Grienauer Ben de aynısını yaptım, zaten paylaştığınızı bilmiyordum! Tek
farkım

7

Sayesinde Phrogz 'ın ve Ephemer harikadır cevapları burada bir SUKDÖ'nün fonksiyonudur automagicallylar iyi eşdeğer RGBA rengini hesaplar.

İstenilen renk ve mevcut arka planla çağırırsınız ve her RGB bileşeninin ± 1 / 256'sı içinde (yuvarlama hataları nedeniyle) istenen sonucu veren en iyi (yani en şeffaf) eşdeğer RGBA rengini hesaplar:

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

Birkaç kombinasyona (tüm Bootswatch temaları) karşı test ettim ve hem karanlıkta koyu hem de karanlıkta açık sonuçlar için bir muamele yapıyor.

Not: Elde edilen renkte ± 1 / 256'dan daha iyi bir hassasiyete ihtiyacınız varsa, rgba renklerini karıştırırken ne tür yuvarlama algoritması tarayıcılarının uyguladığını bilmeniz gerekir (bunun standartlaştırılmış olup olmadığını bilmiyorum) ve uygun bir mevcut olana koşar, böylece istenen hassasiyeti elde edene kadar @whileartmaya $alphadevam eder.


2
Bilginize, bu işlev Stylus'ta şu şekilde mevcuttur transparentify(): stylus-lang.com/docs/bifs.html#transparentifytop-bottom-alpha ... bunu manuel olarak
Stylus'a taşıdıktan

6

@Phrogz'un cevabından:

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

Yani:

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

Yani:

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

Eğer herhangi bir değer seçebilirsiniz Not a1ve bunun karşılık gelen değerleri bulacaksınız r1, g1ve b1gerekli. Örneğin, 1 alfa seçmek size RGB1 = RGB3'e ihtiyacınız olduğunu söyler, ancak 0'ın alfa seçilmesi hiçbir çözüm sağlamaz (tabii ki).


1

Şimdiye kadar bulduğum en pratik çözüm: sadece ortaya çıkan rengi bir renk seçici aracıyla ölçün ve ardından kaplama için ölçülen rengi kullanın. Bu yöntem mükemmel bir renk uyumu sağlar.

Farklı mixinler kullanmayı denedim, ancak yuvarlama hatası nedeniyle farkı hala çıplak gözle görebiliyordum


1
OP muhtemelen belirlemeyi dinamik olarak yapmanın bir yolunu istedi, ancak bu özellikle belirtilmedi ve cevabınız statik renk / alfa seçimleri için iyi bir hack veriyor.
Erik Knowles

0

@ Tobia'nın yanıtını genişletmek ve opaklığı daha çok transparentify gibi belirtmeye izin vermek için:

@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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.