Javascript 在白色上将 RGB 转换为 RGBA
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6672374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert RGB to RGBA over white
提问by Mark Kahn
I have a hex color, e.g. #F4F8FB
(or rgb(244, 248, 251)
) that I want converted into an as-transparent-as-possiblergba color (when displayed over white). Make sense? I'm looking for an algorithm, or at least idea of an algorithm for how to do so.
我有一个十六进制颜色,例如#F4F8FB
(或rgb(244, 248, 251)
),我想将其转换为尽可能透明的rgba 颜色(当显示为白色时)。有道理?我正在寻找一种算法,或者至少是关于如何这样做的算法的想法。
For Example:
例如:
rgb( 128, 128, 255 ) --> rgba( 0, 0, 255, .5 )
rgb( 152, 177, 202 ) --> rgba( 50, 100, 150, .5 ) // can be better(lower alpha)
Ideas?
想法?
FYI solution based on Guffa's answer:
基于 Guffa 回答的 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)'
}
采纳答案by Guffa
Take the lowest color component, and convert that to an alpha value. Then scale the color components by subtracting the lowest, and dividing by the alpha value.
取最低的颜色分量,并将其转换为 alpha 值。然后通过减去最低值并除以 alpha 值来缩放颜色分量。
Example:
例子:
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
So, rgb(152, 177, 202)
displays as rgba(0, 62, 123, .404)
.
因此,rgb(152, 177, 202)
显示为rgba(0, 62, 123, .404)
。
I have verified in Photoshop that the colors actually match perfectly.
我已经在 Photoshop 中验证颜色实际上完美匹配。
回答by gereeter
Let r, g, and b be the input values and r', g', b', and a' be the output values, all scaled (for now, as it makes the math prettier) between 1 and 0. Then, by the formula for overlaying colors:
设 r、g 和 b 是输入值,r'、g'、b' 和 a' 是输出值,都在 1 和 0 之间缩放(现在,因为它使数学更漂亮)。然后,通过叠加颜色的公式:
r = a' * r' + 1 - a'
g = a' * g' + 1 - a'
b = a' * b' + 1 - a'
The 1 - a' terms represent the background contribution, and the other terms represent the foreground. Do some algebra:
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
Intuitively, it seems that the minimum color value will be the limiting factor in the problem, so bind this to m:
直观上,似乎最小颜色值将成为问题的限制因素,因此将其绑定到 m:
m = min(r, g, b)
Set the corresponding output value, m', to zero, as we want to maximize transparency:
将相应的输出值 m' 设置为零,因为我们希望最大化透明度:
0 = (m - 1) / a' + 1
-1 = (m - 1) / a'
-a' = m - 1
a' = 1 - m
So, in javascript (translating from 1 to 255 along the way):
因此,在 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];
}
Note that I'm assuming that a' is opacity here. It is trivial to change it to transparency - just remove the "1 -" from the formula for a'. Anothing thing to note is that this does not seem to produce exact results - it said that the opacity was 0.498 for the example you gave above (128, 128, 255). However, this is extremely close.
请注意,我在这里假设 a' 是不透明度。将其更改为透明度是微不足道的 - 只需从 a' 的公式中删除“1 -”。需要注意的一点是,这似乎并没有产生确切的结果 - 它说你上面给出的例子的不透明度是 0.498 (128, 128, 255)。然而,这是非常接近的。
回答by Stefan
For those of you using SASS/SCSS, I've wrote a small SCSS function so you can easily use the algorithm described by @Guffa
对于那些使用 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
);
}
回答by lxa
I'd look to RGB<->HSL conversion. I.e. luminosity == amount of white == amount of transparency.
我会寻找 RGB<->HSL 转换。即亮度==白色的数量==透明度的数量。
For your example rgb( 128, 128, 255 )
, we need to shift RGB values to 0
first by maximum amount, i.e. to rgb( 0, 0, 128 )
- that would be our color with as few of white as possible. And after that, using formula for luminance, we calculate amount of white we need to add to our dark color to get original color - that would be our alpha:
对于您的示例rgb( 128, 128, 255 )
,我们需要将 RGB 值0
按最大量移动到第一个,即到rgb( 0, 0, 128 )
- 这将是我们的颜色尽可能少的白色。之后,使用亮度公式,我们计算需要添加到深色以获得原始颜色的白色数量 - 这将是我们的 alpha:
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;
Hope that makes sense. :)
希望这是有道理的。:)
回答by Kerrek SB
I'm just describing an idea for the algorithm, no full solution:
我只是描述算法的一个想法,没有完整的解决方案:
Basically, you have three numbers x
, y
, z
and you are looking for three new numbers x'
, y'
, z'
and a multiplier a
in the range [0,1] such that:
基本上,你有三个数字x
,y
,z
和你正在寻找三个新的数字x'
,y'
,z'
和乘数a
范围在[0,1]这样的:
x = a + (1 - a) x'
y = a + (1 - a) y'
z = a + (1 - a) z'
This is written in units where the channels also take values in the range [0,1]. In 8bit discrete values, it'd be something like this:
这是以通道也采用 [0,1] 范围内的值的单位编写的。在 8 位离散值中,它会是这样的:
x = 255 a + (1 - a) x'
y = 255 a + (1 - a) y'
z = 255 a + (1 - a) z'
Moreover, you want the largest possible value a
. You can solve:
此外,您想要最大的可能值a
。你可以解决:
a = (x - x')/(255 - x') x' = (x - 255 a)/(1 - a)
Etc. In real values this has infinitely many solutions, just plug in any real number a
, but the problem is to find a number for which the discretization error is minimal.
等等。在实数值中,这有无限多个解,只需插入任何实数a
,但问题是找到一个离散化误差最小的数字。
回答by trutheality
This should do it:
这应该这样做:
let x = min(r,g,b)
a = 1 - x/255 # Correction 1
r,g,b = ( (r,g,b) - x ) / a # Correction 2
回答by Arvydas Juskevicius
The top answer didn't work for me with low color components. For example it does not calculate correct alpha if color is #80000. Technically it should make it into #ff0000 with alpha 0.5. To resolve this, you need to use RGB -> HSL -> RGBA conversion. This is pseudo code to get the correct values:
对于低颜色组件,最佳答案对我不起作用。例如,如果颜色为 #80000,它不会计算正确的 alpha。从技术上讲,它应该使用 alpha 0.5 使其成为#ff0000。要解决这个问题,您需要使用 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" will contain the value of the new adjusted color and use "alpha" variable to control the transparency.
“newRgb”将包含新调整颜色的值并使用“alpha”变量来控制透明度。