Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何使用alpha输入计算两种颜色的柔和灯光混合值?_Javascript_Colors_Sass_Photoshop_Color Blending - Fatal编程技术网

Javascript 如何使用alpha输入计算两种颜色的柔和灯光混合值?

Javascript 如何使用alpha输入计算两种颜色的柔和灯光混合值?,javascript,colors,sass,photoshop,color-blending,Javascript,Colors,Sass,Photoshop,Color Blending,我需要编写一个JavaScript函数和一个SASSmixin来计算带有alpha输入的两种颜色的柔和灯光混合值 函数/mixin将采用以下三个参数: 背景/基色值 前景色/顶色值 前景色/顶色的Alpha值 并将返回混合颜色 理想情况下,该函数将如下所示: function soft_light(bgcol, fgcol, alpha) { return soft_light_blended_color; } 以下是中关于柔和灯光混合模式的参考资料。我的目标是Photoshop使

我需要编写一个JavaScript函数和一个SASSmixin来计算带有alpha输入的两种颜色的柔和灯光混合值

函数/mixin将采用以下三个参数:

  • 背景/基色值
  • 前景色/顶色值
  • 前景色/顶色的Alpha值
并将返回混合颜色

理想情况下,该函数将如下所示:

function soft_light(bgcol, fgcol, alpha) {
    return soft_light_blended_color;
}
以下是中关于柔和灯光混合模式的参考资料。我的目标是Photoshop使用的公式

我不明白这个公式将如何计算。为什么
b
的值介于
0
1
之间,而不是颜色代码?伽马校正是如何工作的?我将如何执行基本运算,如乘法,减法,在公式中使用的颜色值


非常感谢您提供解决方案指南。提前感谢。:-)

好吧,你提到的是一个被许多人认为是简单的领域,但(或“用于量化和物理描述人类颜色感知的科学和技术”)实际上是一个非常复杂的领域,其整个范围被相对较少的人理解

这听起来可能很吓人,但不用担心,我们不需要了解这项任务的全部内容

缺少规范化值 让我们从为什么0到1开始:这表示独立于位分辨率的标准化值(即8位、10位分量值等)。线性化过程也需要它(例如,gamma和颜色空间),否则我们最终会得到非常错误的值。它还减少了处理时由于是浮点而产生的舍入误差。缺点当然是性能下降和一些内存开销

伽马射线短路 如果使用的是图像源,则需要知道并使用伽马值。如果图像存储为sRGB,则可以。虽然它不是100%准确,但对于这个目的来说已经足够了

Gamma是一种对数补偿,以匹配亮度在屏幕(CRT、LCD等)上的显示方式,当你有灰度梯度时,我们的人眼实际上会感觉到它从黑色到白色均匀地发展

然而,所有成分和混合都需要线性值(上述梯度的中间值实际上是127-128)才能产生正确的结果,因此我们首先需要对这些值进行归一化并应用反伽马(在伪代码中-我使用
Col
表示所有组件,但每个步骤必须分别应用于每个组件):

第一步(可选) 如果准确度不那么重要,性能更重要,您可以跳过这些步骤

var normCol = col / 255;    // 255 for 8-bit values
然后应用逆伽马(解码伽马):

现在,我们通常会使用LUT(查找表)来进行gamma转换,但为了清晰起见,我会将其保持为这样(在这种情况下,您会在值被规格化之前使用它,否则它不是很有用)

混合和Photoshop公式 现在我们可以处理颜色。混合通常只应用于前景(
b
source
),因此我们还不必担心背景和alpha

维基百科文章中的公式是我见过的一个自称是Photoshop公式的版本

例如,我拥有的一个是这样的:

newCol.r = fgcol.r < 0.5 ? 
  2 * bgcol.r * fgcol.r + bgcol.r * bgcol.r * (1 - 2 * fgcol.r) :
  2 * bgcol.r * (1 - fgcol.r) + Math.sqrt(bgcol.r) * (2 * fgcol.r - 1);

newCol.b = fgcol.b < 0.5 ? 
  2 * bgcol.b * fgcol.b + bgcol.b * bgcol.b * (1 - 2 * fgcol.b) :
  2 * bgcol.b * (1 - fgcol.b) + Math.sqrt(bgcol.b) * (2 * fgcol.b - 1);

// etc.

维基百科看起来是这样的:

newCol.r = fgcol.r < 0.5 ? 
  2 * bgcol.r * fgcol.r + bgcol.r * bgcol.r * (1 - 2 * fgcol.r) :
  2 * bgcol.r * (1 - fgcol.r) + Math.sqrt(bgcol.r) * (2 * fgcol.r - 1);

newCol.b = fgcol.b < 0.5 ? 
  2 * bgcol.b * fgcol.b + bgcol.b * bgcol.b * (1 - 2 * fgcol.b) :
  2 * bgcol.b * (1 - fgcol.b) + Math.sqrt(bgcol.b) * (2 * fgcol.b - 1);

// etc.

除此之外,您还可以在浏览器中实现(IIRC许多混合公式都是Adobe“捐赠”的,所以..)

合成 现在我们有了新的混合前景,是时候使用alpha值在背景上合成它了。我们将使用该标准,就像混合模式一样。我们可以使用W3C,它使用标准Porter Duff:

最后,我们可能需要一个alpha混合步骤(检查您的案例)

在当前伪函数中,这将转换为:

function soft_light(bgcol, fgcol, alpha) {
  // Blending
  var newCol;
  if (fgcol < 0.5) {
    newCol = 2 * bgcol * fgcol + bgcol * bgcol * (1 - 2 * fgcol);
  }
  else {
    newCol = 2 * bgcol * (1 - fgcol) + Math.sqrt(bgcol) * (2 * fgcol - 1);
  }

  // Composition
  var as = alpha; // just for clarity. Value in range [0, 1]
  var ab = 1;     // assumes full opaque background here, otherwise use actual alpha of bg
  var Fb = 1 - as;
  newCol = as * newCol + ab * Fb * bgcol;

  // Alpha blending (you may not need this step)
  var a = as + ab * Fb;
  return a ? newCol / a : 0;
}
总结 总之,步骤如下:

  • 将位图/颜色规格化为范围[0,1]*
  • 应用反伽马射线*
  • 调和
  • 复合材料
  • [α混合]
  • 应用伽马射线*
  • 转换回位范围[0,255]*
*:如果可以牺牲准确性,但不能牺牲性能,则可以跳过

例如,颜色为:

var fgcol = {
  r: rn,
  g: gn,
  b: bn
};
因此,混合代码实际上如下所示:

newCol.r = fgcol.r < 0.5 ? 
  2 * bgcol.r * fgcol.r + bgcol.r * bgcol.r * (1 - 2 * fgcol.r) :
  2 * bgcol.r * (1 - fgcol.r) + Math.sqrt(bgcol.r) * (2 * fgcol.r - 1);

newCol.b = fgcol.b < 0.5 ? 
  2 * bgcol.b * fgcol.b + bgcol.b * bgcol.b * (1 - 2 * fgcol.b) :
  2 * bgcol.b * (1 - fgcol.b) + Math.sqrt(bgcol.b) * (2 * fgcol.b - 1);

// etc.
newCol.r=fgcol.r<0.5?
2*bgcol.r*fgcol.r+bgcol.r*bgcol.r*(1-2*fgcol.r):
2*bgcol.r*(1-fgcol.r)+数学sqrt(bgcol.r)*(2*fgcol.r-1);
newCol.b=fgcol.b<0.5?
2*bgcol.b*fgcol.b+bgcol.b*bgcol.b*(1-2*fgcol.b):
2*bgcol.b*(1-fgcol.b)+数学sqrt(bgcol.b)*(2*fgcol.b-1);
//等等。

免责声明:由于范围太大,我没有测试上面的代码和公式是否有错误,我也不打算写所有的代码。即使有错误,你也应该了解大致情况。如果有人发现错误,请随时直接更新帖子或发表评论。

好吧,你提到的是一个被许多人认为很简单的领域,但是(或)“用于量化和物理描述人类颜色感知的科学和技术。”)实际上是一个非常复杂的领域,其整个范围被相对较少的人理解

这听起来可能很吓人,但不用担心,我们不需要了解这项任务的全部内容

缺少规范化值 让我们从为什么0到1开始:这表示独立于位分辨率的标准化值(即8位、10位分量值等)。线性化过程也需要它(例如伽马和颜色空间)或者我们最终会得到非常错误的值。它还减少了由于是浮点而在处理时的舍入误差。缺点是
var gamma = 2.2;
var normCol = Math.pow(newCol, gamma);

var finalCol = (normCol * 255)|0;  // scale and convert to integer+floor
var fgcol = {
  r: rn,
  g: gn,
  b: bn
};
newCol.r = fgcol.r < 0.5 ? 
  2 * bgcol.r * fgcol.r + bgcol.r * bgcol.r * (1 - 2 * fgcol.r) :
  2 * bgcol.r * (1 - fgcol.r) + Math.sqrt(bgcol.r) * (2 * fgcol.r - 1);

newCol.b = fgcol.b < 0.5 ? 
  2 * bgcol.b * fgcol.b + bgcol.b * bgcol.b * (1 - 2 * fgcol.b) :
  2 * bgcol.b * (1 - fgcol.b) + Math.sqrt(bgcol.b) * (2 * fgcol.b - 1);

// etc.