A.N*_*lam 1 javascript photoshop sass colors color-blending
我需要编写一个JavaScript函数和一个SASS mixin来计算带有alpha输入的两种颜色的Soft Light混合值.
函数/ mixin将采用如下三个参数:
并将返回混合颜色.
理想情况下,该功能将如下所示:
function soft_light(bgcol, fgcol, alpha) {
return soft_light_blended_color;
}
Run Code Online (Sandbox Code Playgroud)
以下是维基百科的Soft Light混合模式的参考资料.我的目标是Photoshop使用的公式.
我无法理解如何计算公式.为什么值b介于两者之间0而1不是颜色代码?该如何伽玛校正事工作吗?我将如何执行基本操作,如公式中使用的乘法,减法与颜色值.
该解决方案的指南非常感谢.提前致谢.:-)
小智 5
好吧,你正在触及许多人认为很简单的区域,但比色法(或"用于量化和描述人类色彩感知的科学和技术.")实际上是一个非常复杂的区域,其整个范围都可以通过相对较少.
这可能听起来很可怕,但不用担心,我们不需要为此任务了解其全部内容.
让我们从0到1开始:这表示与位分辨率无关的归一化值(即8位,10位分量值等).线性化过程(例如伽玛和颜色空间)也需要它,否则我们最终会得到非常错误的值.由于浮点,它还减少了处理时的舍入误差.缺点当然是性能损失和一些内存开销.
如果您正在使用图像源,则需要知道并使用伽玛值.如果图像存储为sRGB,则可以假设值为2.2.虽然它不是100%准确,但它足以达到此目的.
Gamma是对数线性颜色值的对数补偿,以匹配亮度在屏幕上显示的方式(CRT,LCD等)并应用,以便当您具有灰度梯度时,它实际上将被视为均匀进展我们的人眼从黑到白.
但是,所有合成和混合都需要线性值(上述渐变的中间值实际上是127-128)才能产生正确的结果,所以我们首先需要对这些值进行归一化并应用反伽马(伪代码 - 我是使用Col以表示所有组件,但各步骤需要单独应用于每个分量):
如果准确性不那么重要且性能更重要,您可以跳过这些步骤.
var normCol = col / 255; // 255 for 8-bit values
Run Code Online (Sandbox Code Playgroud)
然后应用反伽玛(解码伽玛):
var invGamma = 1 / 2.2; // assumes sRGB
var normColLin = Math.pow(normCol, invGamma);
Run Code Online (Sandbox Code Playgroud)
现在,我们通常会使用LUT(查找表)来进行伽马转换,但为了清楚起见,我会保留它(在这种情况下,你会在值被规范化之前使用它,否则它不是很有用).
现在我们可以处理颜色了.混合通常仅应用于前景(b或source),因此我们不必担心背景和alpha.
维基百科文章中的公式是我见过的一个声称是Photoshop公式的版本.
例如,我拥有的那个看起来像这样:

维基百科看起来像这样:
最重要的是你有W3C版本在浏览器中实现(IIRC许多混合公式由Adobe"捐赠",所以..).
Run Code Online (Sandbox Code Playgroud)if(Cs <= 0.5) B(Cb, Cs) = Cb - (1 - 2 x Cs) x Cb x (1 - Cb) else B(Cb, Cs) = Cb + (2 x Cs - 1) x (D(Cb) - Cb) with if(Cb <= 0.25) D(Cb) = ((16 * Cb - 12) x Cb + 4) x Cb else D(Cb) = sqrt(Cb)
但是让我们坚持你引用的那个(如果你检查Photoshop及其结果,你可以随时用另一个替换它以查看哪个匹配最多).另请参阅本文中显示的公式的讨论.
仍为伪(记住维基百科文章中的b前景/顶层和a背景/底层):
// todo normalizing + inverse gamma (apply once to entire bitmaps)
function soft_light(bgcol, fgcol, alpha) {
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);
}
// todo Composition
// todo Alpha blending (maybe)
}
// todo gamma + scale
Run Code Online (Sandbox Code Playgroud)
现在我们有了新的混合前景,现在是时候使用alpha值在背景上合成它了.我们将使用标准的source-over方法,与往常一样使用混合模式.我们可以使用使用标准Porter-Duff的W3C:
Run Code Online (Sandbox Code Playgroud)Fa = 1; Fb = 1 – ?s co = ?s x Cs + ?b x Cb x (1 – ?s) ?o = ?s + ?b x (1 – ?s)
我们可能最后需要一个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;
}
Run Code Online (Sandbox Code Playgroud)
然后我们需要再次应用gamma,以便我们将线性转换回对数以进行显示(您的浏览器可能已经为您进行了伽马编码以用于显示目的,但是如果您需要将其保存出来...):
var gamma = 2.2;
var normCol = Math.pow(newCol, gamma);
var finalCol = (normCol * 255)|0; // scale and convert to integer+floor
Run Code Online (Sandbox Code Playgroud)
总而言之,步骤是:
*:如果可以牺牲精度,但可以牺牲性能,可以跳过.
颜色将是例如:
var fgcol = {
r: rn,
g: gn,
b: bn
};
Run Code Online (Sandbox Code Playgroud)
所以混合代码实际上看起来像这样:
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.
Run Code Online (Sandbox Code Playgroud)
免责声明:由于范围较大,我没有测试代码,上面的公式是错误的,我不打算写下所有代码.即使有错误,你也应该得到一般的想法.如果有人发现错误,请随时直接更新帖子或发表评论.
| 归档时间: |
|
| 查看次数: |
141 次 |
| 最近记录: |