问题描述
The spec for blend-mode saturation 说:
创建具有源色饱和度和背景色色相和亮度的颜色。
最初我认为它会是 HSL,因为这是您可以在具有饱和度通道的 Web 开发中使用的唯一颜色空间,但显然不是:
.color {
width: 100px;
height: 100px;
}
.expected-color {
background: hsl(270,25%,50%);
}
.backdrop-color {
background: hsl(270,85%,50%);
}
.source-color {
mix-blend-mode: saturation;
background: hsl(45,50%);
}
Expected
<div class="color expected-color"></div>
Actual
<div class="color backdrop-color">
<div class="color source-color"></div>
</div>
演示 HSV/HSB 并不容易,但我使用颜色转换器(例如 link)进行的测试表明它也不是那种颜色空间。
.color {
width: 100px;
height: 100px;
}
.expected-color {
/* HSB/HSV - 270,25,50 */
background: #706080;
}
.backdrop-color {
/* HSB/HSV - 270,85,50 */
background: #491380;
}
.source-color {
/* HSB/HSV - 45,50 */
mix-blend-mode: saturation;
background: #807860;
}
Expected
<div class="color expected-color"></div>
Actual
<div class="color backdrop-color">
<div class="color source-color"></div>
</div>
同样,LCH (converter) 没有饱和通道,但它的色度通道实际上是饱和度的模拟:
.color {
width: 100px;
height: 100px;
}
.expected-color {
/* LCH - 50,270 */
background: rgb(90,121,161);
}
.backdrop-color {
/* LCH - 50,270 */
background: rgb(0,125,255);
}
.source-color {
/* LCH - 50,45 */
mix-blend-mode: saturation;
background: rgb(157,107,90);
}
Expected
<div class="color expected-color"></div>
Actual
<div class="color backdrop-color">
<div class="color source-color"></div>
</div>
似乎在 Edge、Chrome 和 Firefox 之间保持一致。
那么 mix-blend-mode: saturation
定义在什么颜色空间中?还是我误解了它的工作原理?
解决方法
我做了一些(很多)更多的挖掘,看起来他们使用的数学是不同色彩空间与一般色彩理论相结合的奇怪组合:
规范中描述的饱和函数是:
B(Cb,Cs) = SetLum(SetSat(Cb,Sat(Cs)),Lum(Cb))
其中Cb
是背景色,Cs
是源色;都在 sRGB 空间中(仅表示 R
、G
和 B
在 [0 - 1]
范围内)。
其中使用的函数定义为:
ClipColor(C)
L = Lum(C)
n = min(Cred,Cgreen,Cblue)
x = max(Cred,Cblue)
if(n < 0)
C = L + (((C - L) × L) / (L - n))
if(x > 1)
C = L + (((C - L) × (1 - L)) / (x - L))
return C
Lum(C) = 0.3 x Cred + 0.59 x Cgreen + 0.11 x Cblue
SetLum(C,l)
d = l - Lum(C)
Cred = Cred + d
Cgreen = Cgreen + d
Cblue = Cblue + d
return ClipColor(C)
Sat(C) = max(Cred,Cblue) - min(Cred,Cblue)
SetSat(C,s)
if(Cmax > Cmin)
Cmid = (((Cmid - Cmin) x s) / (Cmax - Cmin))
Cmax = s
else
Cmid = Cmax = 0
Cmin = 0
return C;
我们可以忽略 ClipColor
和 SetX
函数,因为我们实际上只是对确定颜色空间(如果有)感兴趣。哪个离开:
Lum(C) = 0.3 x Cred + 0.59 x Cgreen + 0.11 x Cblue
Sat(C) = max(Cred,Cblue)
什么是Lum
?
函数的名称及其用法可能会让您假设它们指的是亮度,有时归因于 L
中的 HSL
,或者 B
或 { V
中的 {1}}。他们不是。此函数用于确定颜色对人眼的相对亮度。它来自YIQ colorspace:
请注意,第一行 - 将映射到 Y (Luma) 值 - 与 HSB/HSV
公式中的幻数完美匹配(尽管稍微精确一些)。
对比一下:
Lum(C)
中的 B
/V
频道是 HSB/HSV
。
Max(R,G,B)
中的 L
频道是 HSL
。
什么是( Max(R,B) - Min{R,B) ) / 2
?
这显然是饱和度(某种程度的),但它不是来自任何特定色彩空间。它更像是对您如何看待 Sat
色彩空间中的饱和度的抽象。第一个认为这是考虑饱和度的方式的建议似乎来自 this 2003 paper,这主要是对当时现有色彩空间的批评,以及使用自未使用的色彩空间 RGB
的建议。
对比:
IHLS
中的 S
为 HSB/HSV
或 ( Max(R,B) - Min(R,B) ) / Max(R,B)
,如果 0
为 Max(R,B)
。
0
中的 S
是 HSL
或 ( Max(R,B) - L ) / Min(L,1 - L)
,如果 0
是 L
或 1
。 (与上面定义的相同的 0
)。
我从这一切中得出的唯一结论是,L
与色彩空间完全没有关系,而更多地与更一般意义上的“饱和度”有关;以同样的方式,mix-blend-mode: saturation
不一定与任何特定的色彩空间有关,而是一种保留“亮度感知”的方式。
如果我们指出最有可能的候选者,那就是 mix-blend-mode: luminosity
色彩空间,在深入研究之前我从未听说过。规范中对饱和度的过度简化可以称为色度的度量,这是YIQ
和I
通道共同表示的。
对于软件开发人员来说,这些混合模式的命名似乎不可避免地含糊不清,因为他们的目标受众可能是设计师,而不是工程师。
这不是我想要的答案,但似乎确实是答案。
更新
我刚刚与规范的一位编辑(作者?)进行了一次有趣的交流。造成这种混乱的理由是(转述)“Adobe 产品在过去 20 年里一直这样做,这就是人们习惯的”。显然没有必要过多地质疑这种糟糕的推理,但我的印象是该规范主要是对 photoshop 等中实现的现有混合模式的复制粘贴。