Преобразование RGB в RGBA поверх белого
у меня есть шестнадцатеричный цвет, например #F4F8FB (или rgb(244, 248, 251)) что я хочу превращается в как-прозрачный-как-можно цвет rgba (при отображении поверх белого). Есть смысл? Я ищу алгоритм или, по крайней мере, идею алгоритма для того, как это сделать.
Например:
rgb( 128, 128, 255 ) --> rgba( 0, 0, 255, .5 )
rgb( 152, 177, 202 ) --> rgba( 50, 100, 150, .5 ) // can be better(lower alpha)
идеи?
FYI решение, основанное на ответе Гуффа:
function RGBtoRGBA(r, g, b){
if((g == null) && (typeof r === 'string')){
var hex = r.replace(/^s*#|s*$/g, '');
if(hex.length === 3){
hex = hex.replace(/(.)/g, '');
}
r = parseInt(hex.substr(0, 2), 16);
g = parseInt(hex.substr(2, 2), 16);
b = parseInt(hex.substr(4, 2), 16);
}
var min, a = (255 - (min = Math.min(r, g, b))) / 255;
return {
r : r = 0|(r - min) / a,
g : g = 0|(g - min) / a,
b : b = 0|(b - min) / a,
a : a = (0|1000*a)/1000,
rgba : 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')'
};
}
RGBtoRGBA(204, 153, 102) == RGBtoRGBA('#CC9966') == RGBtoRGBA('C96') ==
{
r : 170,
g : 85 ,
b : 0 ,
a : 0.6,
rgba : 'rgba(170, 85, 0, 0.6)'
}
7 ответов:
возьмите самый низкий цветовой компонент и преобразуйте его в Альфа-значение. Затем масштабируйте цветовые компоненты, вычитая самый низкий и деля на альфа-значение.
пример:
152 converts to an alpha value of (255 - 152) / 255 ~ 0.404 152 scales using (152 - 152) / 0.404 = 0 177 scales using (177 - 152) / 0.404 ~ 62 202 scales using (202 - 152) / 0.404 ~ 123и
rgb(152, 177, 202)отображается какrgba(0, 62, 123, .404).Я проверил в Photoshop, что цвета на самом деле идеально совпадают.
пусть r, g и b-входные значения, а r', g', b' и a' - выходные значения, все масштабированные (на данный момент, поскольку это делает математику более красивой) между 1 и 0. Затем по формуле для наложения цветов:
r = a' * r' + 1 - a' g = a' * g' + 1 - a' b = a' * b' + 1 - a'термины 1 - a ' представляют фоновый вклад, а другие термины представляют передний план. Сделайте немного алгебры:
r = a' * (r' - 1) + 1 r - 1 = a' * (r' - 1) (r - 1) / (r' - 1) = a' (r' - 1) / (r - 1) = 1 / a' r' - 1 = (r - 1) / a' r' = (r - 1) / a' + 1интуитивно, кажется, что минимальное значение цвета будет ограничивающим фактором в проблеме, поэтому привязать это к м:
m = min(r, g, b)установите соответствующее выходное значение, m', равным нулю, так как мы хотим максимизировать прозрачность:
0 = (m - 1) / a' + 1 -1 = (m - 1) / a' -a' = m - 1 a' = 1 - mИтак, в javascript (перевод от 1 до 255 по пути):
function rgba(r, g, b) { var a = 1 - Math.min(r, Math.min(g, b)) / 255; return [255 + (r - 255) / a, 255 + (g - 255) / a, 255 + (b - 255) / a, a]; }обратите внимание, что я предполагаю, что это непрозрачность здесь. Тривиально изменить его на прозрачность - просто удалите "1 -" из формулы для a'. Следует отметить, что это, похоже, не дает точных результатов - он сказал, что непрозрачность была 0,498 для примера ты дал выше (128, 128, 255). Однако это очень близко.
Я бы посмотрел на преобразование RGB HSL. Т. е. светимость = = количество белого = = количество прозрачности.
пример
rgb( 128, 128, 255 ), нам нужно переместить значения RGB в0сначала по максимальной сумме, т. е.rgb( 0, 0, 128 )- Это был бы наш цвет с как можно меньшим количеством белого цвета. И после этого, используя формулу для яркости, мы вычисляем количество белого, которое нам нужно добавить к нашему темному цвету, чтобы получить оригинальный цвет - это будет наша Альфа:L = (MAX(R,G,B) + MIN(R,G,B))/2 L1 = (255 + 128) / 2 = 191.5 L2 = (128 + 0) /2 = 64 A = (191,5 - 64) / 255 = 0,5;надеюсь, что это имеет смысл. :)
для тех из вас, кто использует SASS/SCSS, я написал небольшую функцию SCSS, поэтому вы можете легко использовать алгоритм, описанный @Guffa
@function transparentize-on-white($color) { $red: red($color); $green: green($color); $blue: blue($color); $lowestColorComponent: min($red, $green, $blue); $alpha: (255 - $lowestColorComponent) / 255; @return rgba( ($red - $lowestColorComponent) / $alpha, ($green - $lowestColorComponent) / $alpha, ($blue - $lowestColorComponent) / $alpha, $alpha ); }
я просто описываю идею для алгоритма, нет полного решения:
в принципе, у вас есть три числа
x,y,zи вы ищете три новых номеровx',y',z'и множительaв диапазоне [0,1] такой, что:x = a + (1 - a) x' y = a + (1 - a) y' z = a + (1 - a) z'это записывается в единицах, где каналы также принимают значения в диапазоне [0,1]. В 8-битных дискретных значениях это будет что-то вроде этого:
x = 255 a + (1 - a) x' y = 255 a + (1 - a) y' z = 255 a + (1 - a) z'кроме того, вы хотите максимально возможное значение
a. Вы можете решить:a = (x - x')/(255 - x') x' = (x - 255 a)/(1 - a)Etc. В реальных значениях это имеет бесконечно много решений, просто подключите любое реальное число
a, но проблема заключается в том, чтобы найти число, для которого ошибка дискретизации минимальна.
Это должно сделать это:
let x = min(r,g,b) a = 1 - x/255 # Correction 1 r,g,b = ( (r,g,b) - x ) / a # Correction 2
верхний ответ не работал для меня с низкими цветовыми компонентами. Например, он не вычисляет правильную Альфа, если цвет #80000. Технически он должен сделать это в #ff0000 с Альфой 0.5. Чтобы решить эту проблему, вам нужно использовать преобразование RGB -> HSL -> RGBA. Это псевдо-код, чтобы получить правильные значения:
//Convert RGB to HSL hsl = new HSL(rgb) //Use lightness as alpha alpha = hsl.Lightness //For #80000 lightness is 0.5, so we have to take this into account. //Lightness more than 0.5 converts to alpha 1 and below is a linear ratio if (alpha > 0.5) { alpha = 1; } else { alpha = alpha / 0.5; //We need to drop the lightness of the color to 0.5 to get the actual color //that needs to display. Alpha blending will take care of that. hsl.Lightness = 0.5; } newRgb = hsl.convertToRgb()" newRgb "будет содержать значение нового скорректированного цвета и использовать переменную" Альфа " для управления прозрачностью.
Comments