Поиск "эквивалентного" цвета с непрозрачностью
Скажем, у меня есть цвет фона с "лентой", проходящей над ним в другом сплошном цвете. Теперь я хочу, чтобы лента была частично прозрачной, чтобы некоторые детали сливались, но все равно держите ленту "того же цвета" над фоном.
Есть ли способ (легко) определить, для заданной непрозрачности /alpha < 100% цвета ленты, какие значения RGB должны быть идентичны цвету со 100% непрозрачностью над фоном?
Вот картина. Фон rgb(72, 28, 97)
, лента rgb(45, 34, 70)
. Я хочу rgba(r, g, b, a)
для ленты, чтобы она выглядела идентичной этому сплошному цвету.
![enter image description here]()
Ответы
Ответ 1
Смешивание цветов - это просто линейная интерполяция на канал, верно? Таким образом, математика довольно проста. Если у вас 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)
Если они дают разные значения, то вы не можете сделать так, чтобы они точно совпадали, но вы можете усреднить альфы, чтобы получить как можно ближе. Например, в мире нет непрозрачности, которая позволила бы вам поместить зеленый поверх красного, чтобы получить синий.
Ответ 2
i сделал LESS mixin, используя ответ Phrogz. вы вводите:
- как цвет должен выглядеть
- с определенной буквой
- на заданном фоне (по умолчанию белый)
Здесь код:
.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), это означает, что поддерживаются только умеренные уровни прозрачности. Посмотрите, как вы идете с ним.
Ответ 3
Благодаря отличным ответам Phrogz и эфемер, здесь есть функция 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
, пока не достигнет желаемой точности.
Ответ 4
Из ответа @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 не дает никакого решения (очевидно).
Ответ 5
Развернемся с ответом @Tobia и позволим указать непрозрачность, например, 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);
}