Menemukan warna "setara" dengan opasitas

92

Katakanlah saya memiliki warna latar belakang dengan "pita" di atasnya dengan warna solid lain. Sekarang, saya ingin pita menjadi transparan sebagian untuk membiarkan beberapa detail menyatu, tetapi tetap menjaga pita dengan "warna yang sama" di atas latar belakang.

Apakah ada cara untuk (dengan mudah) menentukan, untuk opacity / alpha <100% dari warna pita, nilai RGB apa yang harus identik dengan warnanya dengan 100% opacity di latar belakang?

Ini fotonya. Latar belakangnya adalah rgb(72, 28, 97), pita rgb(45, 34, 70). Saya ingin rgba(r, g, b, a)pita agar tampak identik dengan warna solid ini.

masukkan deskripsi gambar di sini

vicvicvic.dll
sumber
1
Pertanyaan yang sangat mirip dapat ditemukan di sini: stackoverflow.com/questions/6672374/convert-rgb-rgba tetapi perbedaan utamanya adalah bahwa pertanyaan tersebut menentukan warna dasar putih, sedangkan yang ini sewenang-wenang.
BoltClock

Jawaban:

129

Pencampuran warna hanyalah interpolasi linier per saluran, bukan? Jadi, perhitungannya cukup sederhana. Jika Anda memiliki RGBA1 di atas RGB2, hasil visual RGB3 yang efektif adalah:

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

… Dengan saluran alfa dari 0,0 hingga 1,0.

Pemeriksaan kesehatan: jika alpha-nya 0, apakah RGB3 sama dengan RGB2? Iya. Jika alpha adalah 1, apakah RGB3 sama dengan RGB1? Iya.

Jika Anda hanya mengunci warna latar belakang dan warna akhir, ada sejumlah besar warna RGBA (tak terbatas, dalam ruang floating-point) yang dapat memenuhi persyaratan. Jadi, Anda harus memilih warna bilah atau tingkat opasitas yang Anda inginkan, dan mencari tahu nilai lainnya.

Memilih Warna Berdasarkan Alpha

Jika Anda mengetahui RGB3 (warna akhir yang diinginkan), RGB2 (warna latar belakang), dan A1 (berapa banyak opasitas yang Anda inginkan), dan Anda hanya mencari RGB1, maka kita dapat mengatur ulang persamaannya sebagai berikut:

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

Ada beberapa kombinasi warna yang secara teoritis dimungkinkan, tetapi tidak mungkin mengingat rentang RGBA standar. Misalnya, jika latar belakangnya hitam murni, warna persepsi yang diinginkan adalah putih bersih, dan alfa yang diinginkan adalah 1%, maka Anda memerlukan:

r1 = g1 = b1 = 255/0.01 = 25500

… Putih super terang 100 × lebih cerah dari yang tersedia.

Memilih Alpha Berdasarkan Warna

Jika Anda mengetahui RGB3 (warna akhir yang diinginkan), RGB2 (warna latar belakang), dan RGB1 (warna yang ingin Anda ubah opasitasnya), dan Anda hanya mencari A1, maka kami dapat mengatur ulang persamaan sebagai berikut:

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

Jika ini memberikan nilai yang berbeda, Anda tidak dapat membuatnya sama persis, tetapi Anda dapat menghitung rata-rata alfanya untuk sedekat mungkin. Misalnya, tidak ada opasitas di dunia yang memungkinkan Anda memberi warna hijau di atas merah untuk menjadi biru.

Phrogz
sumber
Tidak r1, g1dan b1juga tidak diketahui?
Eric
@ Saya tidak yakin. Saya telah mengedit jawabannya jika tingkat alfa yang diketahui dan warna yang tidak.
Phrogz
Perhatian, saya menggunakan tiga formula pertama Anda di Photoshop untuk menemukan warna apa pada 0.8 alpha ketika satu-satunya warna referensi saya yang lain adalah putih ... Saya harus menggunakan 1 + (1 - a) atau 1.2 untuk menemukan warna yang tepat ...
John William Domingo
1
@Phrogz Saya menggunakan persamaan 'Pilih Warna Berdasarkan Alpha' Anda, dan saya mendapatkan angka negatif (-31) untuk saluran merah. Ketika saya menggunakan negatif sebagai nilai merah, saya mendapatkan hasil yang sama seperti jika saya menggunakan 0 sebagai nilai merah. Adakah cara untuk mengubah negatif ini menjadi sesuatu yang bisa digunakan? Ada petunjuk tentang apa yang terjadi di sini?
Nocturno
Mungkin perhitungan saya salah, tetapi rumus ini menghasilkan hasil yang tidak diharapkan ketika RGB3 = # 163920, RGB2 = #FFFFFF, dan A1 = 0.92; RGB1 yang dihitung = rgb (2, 40, 13), tetapi rgba (2, 40, 13, 0.92) = # 15381F, bukan # 163920.
thdoan
12

saya membuat mixin KURANG menggunakan jawaban Phrogz. Anda memasukkan:

  1. bagaimana warna seharusnya terlihat
  2. dengan alfa tertentu
  3. pada latar belakang tertentu (default putih)

Berikut kodenya:

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

}

Penggunaan seperti ini:

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

Jelas tidak berfungsi untuk kombinasi yang tidak mungkin (seperti yang disebutkan oleh Phrogz), itu berarti hanya transparansi tingkat ringan yang didukung. Lihat bagaimana Anda melakukannya.

ephemer
sumber
1
@mixin bg_alpha_calc ($ required_colour, $ diinginkan_alpha, $ background_colour: putih) {$ r3: merah ($ diinginkan_warna); $ g3: hijau ($ warna_yang diinginkan); $ b3: biru ($ warna_yang diinginkan); $ r2: merah ($ background_colour); $ g2: hijau ($ background_colour); $ b2: biru ($ background_colour); // r1 = (r3 - r2 + r2 * a1) / a1 $ r1: ($ r3 - $ r2 + ($ r2 * $ diinginkan_alpha)) / $ diinginkan_alpha; $ g1: ($ g3 - $ g2 + ($ g2 * $ yang diinginkan_alpha)) / $ yang diinginkan_alpha; $ b1: ($ b3 - $ b2 + ($ b2 * $ yang diinginkan_alpha)) / $ yang diinginkan_alpha; background-color: $ diinginkan_warna; warna-latar belakang: rgba ($ r1, $ g1, $ b1, $ diinginkan_alpha); }
metaColin
2
Saya mengadopsi dan membuat mixin versi SCSS. Temukan demo dan kodenya di sini: codepen.io/Grienauer/pen/Grogdx
Grienauer
@Grienauer Saya melakukan hal yang sama, tidak menyadari Anda sudah membagikannya! Satu-satunya perbedaan saya adalah bahwa saya menetapkan warna latar belakang menjadi putih
tehlivi
7

Berkat Phrogz 's dan Ephemer ' s jawaban yang besar, di sini adalah fungsi SASS yang otomatis menghitung terbaik warna RGBA setara.

Anda menyebutnya dengan warna yang diinginkan dan latar belakang yang ada, dan itu akan menghitung warna RGBA setara terbaik (yang berarti paling transparan) yang memberikan hasil yang diinginkan dalam ± 1/256 dari setiap komponen RGB (karena kesalahan pembulatan):

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

Saya baru saja mengujinya terhadap sejumlah kombinasi (semua tema Bootswatch) dan berfungsi dengan baik, baik untuk hasil gelap-terang dan terang-ke-gelap.

PS: Jika Anda membutuhkan presisi yang lebih baik dari ± 1/256 dalam warna yang dihasilkan, Anda perlu mengetahui jenis algoritma pembulatan apa yang diterapkan browser saat memadukan warna rgba (saya tidak tahu apakah itu terstandarisasi atau tidak) dan tambahkan yang sesuai kondisi eksisting @while, sehingga terus meningkat $alphahingga mencapai presisi yang diinginkan.

Tobia
sumber
2
FYI, fungsi ini ada di Stylus sebagai transparentify(): stylus-lang.com/docs/bifs.html#transparentifytop-bottom-alpha ... yang saya temukan setelah mem-porting ini secara manual ke Stylus ...
weotch
6

Dari jawaban @Phrogz:

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

Begitu:

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

Begitu:

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

Catatan Anda dapat memilih nilai apapun dari a1, dan ini akan menemukan nilai-nilai yang sesuai r1, g1dan b1diperlukan. Misalnya, memilih alfa 1 memberi tahu Anda bahwa Anda memerlukan RGB1 = RGB3, tetapi memilih alfa 0 tidak memberikan solusi (jelas).

Eric
sumber
1

Solusi paling praktis yang saya temukan sejauh ini: cukup ukur warna yang dihasilkan dengan alat pemilih warna, lalu gunakan warna terukur untuk overlay. Metode ini memberikan kecocokan warna yang sempurna.

Saya sudah mencoba menggunakan mixin yang berbeda tetapi karena kesalahan pembulatan, saya masih bisa melihat perbedaannya dengan mata telanjang

executinstaller
sumber
1
OP mungkin menginginkan cara untuk membuat penentuan secara dinamis, tetapi itu tidak disebutkan secara spesifik, dan jawaban Anda memang memberikan peretasan yang baik untuk pilihan warna / alfa statis.
Erik Knowles
0

Untuk memperluas jawaban @ Tobia dan memungkinkan untuk menentukan opacity lebih seperti 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.dll
sumber