Пошук “еквівалентного” кольору з прозорістю


92

Скажімо, у мене є колір фону, на якому "стрічка" проходить в іншому суцільному кольорі. Тепер я хочу, щоб стрічка була частково прозорою, щоб дати змогу поєднуватися деяким деталям, але при цьому зберегти стрічку в "однаковому кольорі" на задньому плані.

Чи є спосіб (легко) визначити для даної непрозорості / альфа <100% кольору стрічки, які значення RGB вони повинні бути ідентичними своєму кольору зі 100% непрозорістю над фоном?

Ось малюнок. Фон є rgb(72, 28, 97), стрічка rgb(45, 34, 70). Я хочу rgba(r, g, b, a)стрічку для того, щоб вона виглядала ідентичною цьому суцільному кольору.

введіть тут опис зображення


1
Дуже подібне запитання можна знайти тут: stackoverflow.com/questions/6672374/convert-rgb-rgba, але ключова відмінність полягає в тому, що це питання вказує базовий колір білого, тоді як цей є довільним.
BoltClock

Відповіді:


129

Змішування кольорів - це просто лінійна інтерполяція на канал, так? Отже, математика досить проста. Якщо у вас RGBA1 над RGB2, ефективним візуальним результатом RGB3 буде:

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

... де альфа-канал становить від 0,0 до 1,0.

Перевірка розумності: якщо альфа дорівнює 0, чи є RGB3 таким самим, як RGB2? Так. Якщо альфа дорівнює 1, чи є RGB3 таким самим, як RGB1? Так.

Якщо ви заблокували лише колір фону та кінцевий колір, існує велика кількість кольорів RGBA (нескінченних, у просторі з плаваючою комою), які можуть задовольнити вимоги. Отже, вам слід вибрати або колір смуги, або рівень непрозорості, який ви хочете, і з’ясувати значення іншого.

Вибір кольору на основі альфи

Якщо ви знаєте RGB3 (остаточний бажаний колір), RGB2 (колір фону) та A1 (скільки непрозорості ви хочете), і ви просто шукаєте RGB1, тоді ми можемо переставити рівняння таким чином:

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

Є кілька поєднань кольорів, які теоретично можливі, але неможливі, враховуючи стандартний діапазон RGBA. Наприклад, якщо фон чисто чорний, бажаний колір, який сприймається, є чисто білим, а бажаний альфа 1%, то вам знадобиться:

r1 = g1 = b1 = 255/0.01 = 25500

... надзвичайно яскравий білий у 100 разів яскравіший, ніж будь-який з наявних.

Вибір альфи на основі кольорів

Якщо ви знаєте RGB3 (остаточний бажаний колір), RGB2 (колір тла) та RGB1 (колір, який ви хочете змінити, непрозорість), і ви просто шукаєте A1, тоді ми можемо перевпорядкувати рівняння таким чином:

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

Якщо вони дають різні значення, то ви не можете змусити це точно відповідати, але ви можете усереднити альфи, щоб наблизитися якомога ближче. Наприклад, у світі немає прозорості, яка дозволила б вам поставити зелений колір над червоним, щоб отримати синій.


Хіба не r1, g1а b1також невідомо?
Ерік

@Eric Я не впевнений. Я відредагував відповідь на випадок, якщо відомий рівень альфа, а кольори - ні.
Phrogz

Зверніть увагу, я використав ваші перші три формули у Photoshop, щоб знайти, яким буде колір у 0,8 альфа, коли моїм єдиним контрольним кольором був білий ... Мені довелося використовувати 1 + (1 - а) або 1,2, щоб знайти правильний колір ...
Джон Вільям Домінго

1
@Phrogz Я використовую ваші рівняння "Виберіть колір на основі альфи", і я отримую від'ємне число (-31) для червоного каналу. Коли я використовую мінус як червоне значення, я отримую той самий результат, як якщо б я використовував 0 як червоне значення. Чи є спосіб перетворити цей негатив на щось корисне? Будь-яка підказка щодо того, що тут відбувається?
Nocturno

Можливо, мої розрахунки вимкнені, але ця формула дає несподіваний результат, коли RGB3 = # 163920, RGB2 = #FFFFFF і A1 = 0,92; обчислений RGB1 = rgb (2, 40, 13), але rgba (2, 40, 13, 0.92) = # 15381F, а не # 163920.
thdoan

12

я зробив МЕНШЕ мікшину, використовуючи відповідь Фрогза. ви вводите:

  1. як повинен виглядати колір
  2. з певною альфою
  3. на заданому тлі (за замовчуванням білий)

Ось код:

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

}

Використання приблизно так:

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

Очевидно, що не працює для неможливих комбінацій (як згадував Phrogz), це означає, що підтримуються лише помірні рівні прозорості. Подивіться, як ви з цим рухаєтесь.


1
@mixin bg_alpha_calc ($ бажаний_барв, $ бажаний_альфа, $ фон_кольору: білий) {$ r3: червоний ($ бажаний_барв); $ g3: зелений ($ бажаний_ колір); $ b3: синій ($ бажаний_ колір); $ r2: червоний ($ background_colour); $ g2: зелений ($ background_colour); $ b2: синій ($ background_colour); // r1 = (r3 - r2 + r2 * a1) / a1 $ r1: ($ r3 - $ r2 + ($ r2 * $ бажана_альфа)) / $ бажана_альфа; $ g1: ($ g3 - $ g2 + ($ g2 * $ бажана_альфа)) / $ бажана_альфа; $ b1: ($ b3 - $ b2 + ($ b2 * $ бажана_альфа)) / $ бажана_альфа; фон-колір: $ бажаний_ колір; фон-колір: rgba ($ r1, $ g1, $ b1, $ бажана_альфа); }
metaColin

2
Я прийняв і створив комбінацію версій SCSS. Знайдіть демо та код тут: codepen.io/Grienauer/pen/Grogdx
Grienauer

@Grienauer Я зробив те саме, не розумів, що ти вже поділився ним! Моя єдина відмінність полягає в тому, що я встановив за
замовчуванням

7

Завдяки Phrogz «s і ephemer » s великих відповідей, тут є функція SASS , яка автоматично обчислює найкращий еквівалентний колір RGBA.

Ви викликаєте його з бажаним кольором та наявним фоном, і він обчислює найкращий (мається на увазі найбільш прозорий) еквівалентний колір RGBA, який дає бажаний результат в межах ± 1/256 кожного компонента RGB (через помилки округлення):

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

Я щойно перевірив його на ряді комбінацій (усі теми Bootswatch), і це чудово підходить, як для темних на світлі, так і для світлих темних результатів.

PS: Якщо вам потрібна краща точність ± 1/256 в отриманому кольорі, вам потрібно буде знати, який алгоритм округлення застосовують браузери при змішуванні кольорів rgba (я не знаю, стандартизовано це чи ні) і додати відповідний умова до існуючого @while, так що воно продовжує зростати, $alphaпоки не досягне бажаної точності.


2
FYI, ця функція існує в Stylus як transparentify(): stylus-lang.com/docs/bifs.html#transparentifytop-bottom-alpha ... яку я виявив після перенесення цього вручну на Stylus ...
weotch

6

З відповіді @Phrogz:

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

Тому:

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

Тому:

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

Зверніть увагу , ви можете вибрати будь-яке значення a1, і це буде знайти відповідні значення r1, g1і b1потрібно. Наприклад, вибір альфа-1 говорить вам, що вам потрібен RGB1 = RGB3, але вибір альфа-0 не дає жодного рішення (очевидно).


1

Найбільш практичне рішення, яке я знайшов на даний момент: просто виміряйте отриманий колір за допомогою інструмента підбору кольору, а потім використовуйте виміряний колір для накладання. Цей метод дає ідеальне поєднання кольорів.

Я пробував використовувати різні міксини, але через помилку округлення я все одно зміг побачити різницю неозброєним оком


1
ОП, напевно, хотів зробити спосіб динамічного визначення, але це не було конкретно зазначено, і ваша відповідь дає хороший хак для статичного вибору кольору / альфа.
Ерік Ноулз,

0

Щоб розширити відповідь @ Tobia і дозволити вказати непрозорість, більше як прозорість:

@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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.