用“色相”混合模式混合两种非不透明颜色

20
我希望按照W3C合成和混合规范中所描述的实现颜色混合(我是用JavaScript编写的,但语言对解决我的问题不太重要)。

回顾一下:在回答这个问题的实现过程中,我意识到这可能会成为一个相当不错的独立软件包。如果您感兴趣,可以从 npm 上获取它。


目前为止它运行得很好,但我想进一步发展这些算法并添加对alpha通道的支持。由于SVG组合规范提供了所有所需的公式,这并不太困难。

但现在我卡在了实现W3C规范中描述为非分离的混合模式上,它们是(如来自Photoshop所知):色相饱和度颜色亮度

可悲的是,这些算法在SVG规范中不可用,我不知道如何处理它们。我猜测有一些修改版的W3C提供的公式用于处理alpha通道,而我可能错过了。

为了更好地展示我的问题,我将展示Photoshop给我提供的两种颜色混合的色相

Photoshop hue blending example of two opaque colors

我也能够使用W3C规范中提到的非透明度算法复现出这个结果。

但是,我无法像Photoshop在源颜色和背景颜色上均设置较低的透明度时所给出的结果:

Photoshop hue blending example of two colors with 60% opacity each

有人知道如何通过编程实现这个结果吗?

更新1: 更改插图(添加HSVA和RGBA代码)以澄清使用的颜色。

更新2: 为了检查可能的解决方案,我附加了另外两个由Photoshop生成的混合示例:

Photoshop hue blending example of two colors with different opacity combinations

Photoshop hue blending example of two colors with different opacity combinations

更新3: 结果证明,除了对颜色混合没有头绪外,我还搞砸了我的Photoshop设置,使得解决我的问题变得更加困难。为可能的未来路人修复示例图像。


1
我在1997年花了很长时间逆向工程所有的Photoshop混合模式,包括alpha的效果。不幸的是,这一切都属于一个我已经多年没有工作过的公司的财产。 - Mark Ransom
你的示例中的hsla数字是由Photoshop或其他软件生成的吗?我注意到它们与w3链接中的公式中的数字不太相似。而且,在那个链接中的“SetSat”函数在我看来完全是错误的。 - Mark Ransom
1
有没有可能提供一些例子,然后尝试从结果中猜测方程式呢?数学上,我假设我们有一个函数,它接受8个参数(4个源和4个背景),并返回4个变量,这正确吗? - piotrwest
我正在使用JavaScript进行此操作,并且我想在JavaScript中实现它,是的。但语言并不那么重要,因为它最终都应该归结为数学。 - Loilo
1
@MarkRansom 哇,看来我的图片处理太不小心了...我会修复的。当然你可以回答这个问题,但我不确定它会包含什么内容,因为Christos Lytras的回答已经说得很清楚了。不过我会附上另一个例子。 - Loilo
显示剩余14条评论
2个回答

17
你在第二张图片中使用的色相 alpha 值并不代表 alpha 颜色合成公式,而是反映了 Porter Duff alpha composition 中定义的 Source Over,在此处9.1.4. Source Over使用以下公式:

Source Over Formula

如果您想实现这种混合效果,而不是适当的色调混合,您可以使用以下JavaScript公式:
PDso = { // Ported Duff Source Over
    r: ((S.r * S.a) + (B.r * B.a) * (1 - S.a)) / aR,
    g: ((S.g * S.a) + (B.g * B.a) * (1 - S.a)) / aR,
    b: ((S.b * S.a) + (B.b * B.a) * (1 - S.a)) / aR,
};

// where
// S : the source rgba
// B : the backdrop rgba
// aR : the union alpha (as + ab * (1 - as))

带透明通道的色相混合模式

这是我在Photoshop中创建的使用alpha颜色合成公式的确切色相混合源覆盖背景的截图:

Photoshop Hue Blend Mode

中间方格上的绿色高亮字母是正确的混合表示。这是使用新的CSS mix-blend-mode将源颜色放在背景颜色内的CSS色调混合(运行代码片段):

.blends div {
    width:140px;
    height:140px;
}

.source {
    mix-blend-mode: hue;
}

.backdrop.alpha {
    background-color: rgba(141, 214, 214, .6);
    isolation: isolate;
}

.source.alpha {
    background-color: rgba(255, 213, 0, .6);
}
<div id="main">
 
 <div class="blends alpha">
  <div class="backdrop alpha">
   <div class="source alpha"></div>
  </div>
 </div>

</div>

如果您使用取色器,您将获得几乎相同的值(211、214、140 <> 210、214、140)。这可能是由于略有不同的算法或不同的舍入方法,但这并不重要。事实上,这是混合带有色调混合模式的 alpha 颜色的正确结果。
因此,现在我们需要公式来应用于我们的色调混合模式的 alpha 颜色组合,以获得适当的颜色值。我进行了一些搜索,并在 Adobe 文档管理 - 便携式文档格式 - 第 1 部分:PDF 1.7 中找到了所有内容。我们可以在第328页的混合模式后找到颜色组合公式

11.3.6 Alpha 的解释

颜色合成公式

颜色合成公式

这是我得到的公式,可以更好地匹配带有alpha通道的Photoshop色相混合模式。我用JavaScript写成了以下形式:
function Union(ab, as) {
    return as + ab * (1 - as);
}

function colourCompositingFormula(as, ab, ar, Cs, Cb, Bbs) {
    return (1 - (as / ar)) * Cb + (as / ar) * Math.floor((1 - ab) * Cs + ab * Bbs);
}

var aR = Union(B.a, S.a); // αr = Union(αb, αs) // Adobe PDF Format Part 1 - page 331

var Ca = {
    // Adobe PDF Format Part 1 - page 328
    r: colourCompositingFormula(S.a, B.a, aR, S.r, B.r, C.r),
    g: colourCompositingFormula(S.a, B.a, aR, S.g, B.g, C.g),
    b: colourCompositingFormula(S.a, B.a, aR, S.b, B.b, C.b)
};

// where
// C : the hue blend mode result rgb
// S : the source rgba
// B : the backdrop rgba
// aR : the union alpha (as + ab * (1 - as))
// Ca : the final result

body {
  padding:0;
  margin:0;
}

iframe {
  width: 100%;
  height: 200px;
  border:0;
  padding:0;
  margin:0;
}
<iframe src="https://zikro.gr/dbg/html/blending-modes/"></iframe>

我的测试示例可以在这里找到。在2.5带Alpha的(色调混合算法计算)中,您可以看到带透明度的最终色调混合模式结果。它的值与Photoshop结果略有不同,但我在Fireworks中混合源和背景颜色的色调得到了完全相同的结果(202, 205, 118)。

Fireworks same result

所有应用程序都有自己略微不同的算法,也许我使用的公式比较旧,也许有最新版本。


哇,我对这个答案所付出的巨大努力印象深刻。我用不同的颜色和不透明度测试了你的算法,结果的准确性在各个方面都大致相同。我必须承认,与 Photoshop 的偏差(正如你所解释的,CSS 也会创建)有点让人烦恼。然而,在赏金期限还剩下几个小时的情况下,如果没有更准确的答案,你肯定会赢得这个奖励。 - Loilo
是的,我知道那些赏金。我只是粗略地查看了赏金常见问题解答,这就是为什么我没有完全正确理解(关于如果没有答案会退还赏金的问题)。经过一番思考,不退还赏金是完全有道理的。关于你的回答-我本来打算等待一个可能更准确的算法,但由于赏金已经进入宽限期,我想直接接受你的回答也是公平的。 - Loilo
@Loilo 谢谢。我会检查更准确的公式,而且我很惊讶 Adobe Fireworks 生成的值与 Photoshop 稍有不同(即使是 +-1 R)!你想要我的 Hue blendingColor Hsl/Rgb 的 JavaScript 文件吗?当然你可以从我的源链接获取它们,但如果你想要,我甚至可以更新答案并提供链接或完整代码。 - Christos Lytras
是的,这就是我从Photoshop CC 2015得到的。你确定你有色相图层源和正常混合模式的背景吗?看一下我的Photoshop颜色选择器信息截图http://zikro.gr/dbg/html/blending-modes/photoshop-ss-1lbl.png。当我用*Fireworks*打开文件(保存为带alpha通道的PNG)时,我读取到了相同的值(`202、206、118、84%`)。 - Christos Lytras
是的,这完全有道理!我在回答开始就告诉过你那里得到的值是错误的。第二个alpha原始图像中的这些不是色相混合值,现在你知道为什么了微笑。要小心,并始终记得在更改设置时将其改回来。我看到了你在http://softwareengineering.stackexchange.com/questions/336794/algorithms-for-color-blending-modes-hue-saturation-color-luminosity上的问题,甚至阅读了关于*Gamma*发布在评论中的文章!我必须承认,那是一个很好的知识来源,但与你的问题无关! - Christos Lytras
显示剩余9条评论

2

从这里开始

色调混合创建一种颜色,该颜色具有源颜色的色调以及背景颜色的饱和度和亮度。

我可以想出一些公式,但它们可能是垃圾,尽管它们完全复制了发布的原始数字:

h: hSource + deltaH * (1 - aSrouce) * aBackdrop * 0.41666666 = 50; 63

s: sBackdrop * 0.9 + deltaS * (1 - aBackdrop) * aSource * 0.20833333 = 45; 47.5

l: lBackdrop * 0.957142857 + deltaL * (1 - aBackdrop) * aSource * 0.77 = 67; 63.3

a: 1 - (1 - aSource)^2 总是匹配


1
我很感激你的努力,但是你的公式只解决了那个特定的情况,对于一般性问题没有任何用处。但是这仍然是一个好主意,可以添加另一个Photoshop生成的混合示例来检查可能的结果。此外,你的公式中至少有一个错误,因为色相和亮度的差值计算有点扭曲(deltaH=hBackdrop-hSource, 但 deltaL=lSource-lBackdrop)。 - Loilo
那个带有增量的逻辑上是一致的。Hue以源为基础,但亮度和饱和度则以背景为基础,因此在这方面情况正好相反。 - maraca

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接