1987WEB视界-分享互联网热点话题和事件

您现在的位置是:首页 > WEB开发 > 正文

WEB开发

[Html5] 彻底搞懂画布合成模式(globalCompositeOperation)的计算公式

1987web2024-03-25WEB开发32
作者:zyl910一、缘由上一篇文章“用于分析26种画布合成模式(globalCompositeOperation)的演示页面”给出了便于测试的演示页面,现在探究一下

作者: zyl910 一、缘由 上一篇文章“用于分析26种画布合成模式(globalCompositeOperation)的演示页面”给出了便于测试的演示页面,现在探究一下合成模式的计算公式。 在网上搜索了一下,发现W3C《Compositing and Blending Level 1》对合成模式 ...

作者: zyl910

一、缘由

上一篇文章“用于分析26种画布合成模式(globalCompositeOperation)的演示页面”给出了便于测试的演示页面,现在探究一下合成模式的计算公式。在网上搜索了一下,发现W3C《Compositing and Blending Level 1》对合成模式的公式说的最详细,于是仔细阅读了该文档。该文档的篇幅比较长,且是英文版的,看起来比较吃力。且有些细节写的比较简略,若忽略了那些细节,可能会导致构造的公式不正确、计算结果不符。于是整理了一下我的心得,编写了此文。

二、《Compositing and Blending Level 1》阅读心得

对于合成模式来说,最重要的内容在该文档的这几个章节——

5.1Simplealpha compositing9Advancedcompositing features10Blending

“5.1 Simple alpha compositing”是介绍最基础的的简单Alpha合成。随后第9、10章是基于这个基础算法,创造了更丰富的合成模式。从第9、10章的标题来看,该文档将合成运算分为了2个大类——

Compositing(合成):最常用的“Source Over”合成就是属于这一类的。画布的26种画布合成模式里,前10种是属于这一类的。Blending(混合):画布的26种画布合成模式里,后16种是属于这一类的。

2.1 简单Alpha合成(“5.1 Simple alpha compositing”)

2.1.1 计算颜色分量

在“5.1 Simple alpha compositing”里,首先说明了如何计算颜色分量,摘录——

Theformulaforsimple alpha compositingisco=Csxαs+Cbxαb x(1-αs)Whereco:the premultiplied pixel value after compositingCs:the color value of the source graphic element being compositedαs:the alpha value of the source graphic element being compositedCb:the color value of the backdropαb:the alpha value of the backdropNote:Allvalues are between0and1inclusive.Thepixel value after compositing(co)isgivenbyadding the contributionsfromthe source graphic element[Csxαs]andthe backdrop[Cbxαb x(1-αs)].Forboth the graphic elementandthe backdrop,the color values are multipliedbythe alpha to determine the amount of color that contributes.Withzero alpha meaning that the color doesnotcontributeandpartialalpha means that some percentage of the color contributes.Thecontribution of the backdropisfurther reduced based on the opacity of the graphic element.Conceptually,(1-αs)of the backdrop shows through the graphic element,meaning thatifthe graphic elementisfully opaques=1)thennobackdrop shows through.

中文翻译——

5.1。简单的alpha合成简单alpha合成的公式是co=Csxαs+Cbxαb x(1-αs)其中co:合成后的预乘像素值cs:正在合成的源图形元素的颜色值αs:正在合成的源图形元素的alphaCb:背景的颜色值αb:背景的alpha注意:所有值都介于01之间。合成后的像素值(co)由源图形元素[Csxαs]和背景[Cbxαb x(1-αs)]的贡献相加得出。对于图形元素和背景,颜色值乘以alpha以确定贡献的颜色量。零alpha意味着颜色没有贡献,部分alpha意味着一定百分比的颜色有贡献。背景的贡献基于图形元素的不透明度进一步减少。从概念上讲,背景的(1-αs)通过图形元素显示,这意味着如果图形元素完全不透明s=1),则没有背景显示。

“x”代表“*”,即乘法运算。c代表颜色(Color)分量。如 R、G、B 分量的值。很多关于Alpha合成的资料中,将 backdrop(背景)称为 Destination(目标)。了解了这一点之后,可以与其他资料进行对照。

2.1.2 计算Alpha分量

该小节随后说明了如何计算Alpha(不透明度)分量。摘录——

Thesimple alpha compositing formula listed above gives a resultant color whichisthe result of the weighted average of the backdrop colorandgraphic element color,withthe weighting determinedbythe backdropandgraphic element alphas.Theresultant alpha value of the compositeissimply the sum of the contributed alpha of the composited elements.Theformulaforthe resultant alpha of the compositeisαo=αs+αb x(1-αs)Whereαo:the alpha value of the compositeαs:the alpha value of the graphic element being compositedαb:the alpha value of the backdrop

中文翻译——

上面列出的简单alpha合成公式给出的结果颜色是背景颜色和图形元素颜色的加权平均结果,权重由背景和图形元素alpha决定。合成的合成alpha值只是合成元素贡献的alpha的总和。合成的结果alpha的公式是αo=αs+αb x(1-αs)其中αo:合成的alphaαs:正在合成的图形元素的alphaαb:背景的alpha

2.1.3 处理预乘(pre-multiplied)

该文档最后说明了如何处理预乘(pre-multiplied)。摘录——

Often,it can be more efficient to store a pre-multiplied valueforthe colorandopacity.Thepre-multiplied valueisgivenbycs=Csxαswithcs:the pre-multiplied valueCs:the color valueαs:the alpha valueThusthe formulaforsimple alpha compositingusingpre-multiplied values becomesco=cs+cb x(1-αs)Toextract the color component of a pre-multiplied value,the formulaisreversed:Co=co/αo

中文翻译——

通常,存储颜色和不透明度的预乘值会更有效。预乘法的值由以下公式给出cs=Csxαs其中cs:预乘值Cs:颜色值αsalpha因此,使用预乘值进行简单alpha合成时,公式变为co=cs+cb x(1-αs)为了从预乘值提取颜色分量,可对公式进行逆向变换:Co=co/αo

2.1.4 小结

初看这一节时可能会有这样的疑问——该章节标题是“简单Alpha合成”,但给出的公式怎么比较复杂。貌似很多资料上的“Alpha合成”公式比较简单。原因在于这一节讲解的是 “源与背景均具有Alpha通道”时的合成算法。而不少资料讲解的仅是“没有Alpha通道时的特例”。没有Alpha通道时,Alpha合成可看作简单的线性插值,计算公式很简单。且不用理会预乘(pre-multiplied)。但源与背景均具有Alpha通道时,就没有这么简单了。需要基于加色法光照模型来推导的,颜色预乘后的结果才是实际的光照贡献值。这就是为什么主公式的计算结果为预乘值的原因。这也是很多资料推荐“用预乘的位图格式”的原因。

而Html5画布为了便于直观使用,规定了位图数据为“非预乘”(not use pre-multiplied、not multiplied。另一种称呼是 Straight,即“直通”)格式的,于是在Alpha混合后需再做一次“预乘值转非预乘值”的转换。

因Html5画布的位图是非预乘的,于是可以总结得到以下经验——

该文中的提到的 源(s:source)、背景(b:backdrop)颜色值,一般是非预乘(not use pre-multiplied)值。该文中的提到的主要公式计算结果,一般是预乘(pre-multiplied)值。最后为了转为Html5规范的位图颜色值,得再做一次“预乘值转非预乘值”的转换。

总结一下,该文的“简单Alpha合成”计算过程,由这3个公式组成——

co=Csxαs+Cbxαb x(1-αs)// 主公式, 得到混合后的已预乘颜色分量值。αo=αs+αb x(1-αs)// 得到混合后的Alpha(不透明度)分量值。Co=co/αo// 对已预乘颜色分量进行“预乘值转非预乘值”转换,得到了非预乘的颜色分量。即转为Html5规范的位图颜色值。

2.2 Compositing类合成模式的算法(9 Advanced compositing features)

Compositing类合成模式,又被称为“The Porter Duff Compositing Operators”。“Porter Duff”是指 Thomas Porter 和 Tom Duff ,他们于 1984 年发表了一篇名为 “Compositing Digital Images”(合成数字图像)的开创性论文。在这篇文章中,两位作者描述了12种合成操作符,具体来说就是当我们把原图像绘制到目标图像处时应该如何计算二者结合后的颜色。

2.2.2 解读“9.1. The Porter Duff Compositing Operators”

《Compositing and Blending Level 1》第9章中的第1节,对此进行了说明:

9.1.ThePorterDuffCompositingOperatorsThelandmark paperbyThomasPorterandTomDuff,who workedforLucasfilm,definedthe algebra of compositinganddeveloped the twelve"Porter Duff"operators.Theseoperators control the results of mixing the foursub-pixel regions formedbythe overlapping of graphical objects that have an alphaorpixel coverage channel/value.Theoperatorsuseall practical combinations of the four regions.Thereare12basicPorterDuffoperators,satisfying all possible combinations of sourceanddestination.Fromthe geometric representation of eachoperator,the contribution of each shape can be seen to be expressedasa fraction of the total coverage of the output.Forexample,insource over,the possible contribution of sourceisfull(1)andthe possible contribution of destinationiswhateverisremaining(1αs).Thisismodifiedbythe coverage of sourceanddestination to give the equationforthefinalcoverage of the pixel:αo=αs x1+αb x(1αs)Thefractional termsFa(1inthisexample)andFb(1αsinthisexample)aredefinedforeachoperatorandspecify the fraction of the shapes that may contribute to thefinalpixel value.Thegeneral form of the equationforcoverageis:αs xFa+αb xFbandincorporating color gives the generalPorterDuffequationco=αs xFaxCs+αb xFbxCbWhere:coisthe output color pre-multipliedwiththe output alpha[0<=co<=1]αsisthe coverage of the sourceFaisdefinedbytheoperatorandcontrols inclusion of the sourceCsisthe color of the source(notmultipliedbyalpha)αbisthe coverage of the destinationFbisdefinedbytheoperatorandcontrols inclusion of the destinationCbisthe color of the destination(notmultipliedbyalpha)

中文翻译——

9.1.波特-达夫合成算子为卢卡斯影业工作的托马斯-波特和汤姆-达夫发表了一篇具有里程碑意义的论文,定义了合成的代数并开发了12"波特-达夫 "算子。这些算子控制着由具有阿尔法或像素覆盖通道/值的图形对象的重叠所形成的四个子像素区域的混合结果。这些算子使用这四个区域的所有实际组合。12个基本的波特-达夫算子,满足源和目的的所有可能组合。从每个算子的几何表示法来看,每个形状的贡献可以被看作是输出的总覆盖率的一部分来表示。例如,在源超过,源的可能贡献是完全的(1),目的地的可能贡献是任何剩余的(1s)。这是由源和目的地的覆盖率修改的,从而得到像素的最终覆盖率的方程式。αo=αs x1+αb x(1-αs)分数项Fa(本例中为1)和Fb(本例中为1s)是为每个算子定义的,并指定了可能对最终像素值有贡献的形状的分数。覆盖率方程的一般形式是。αs xFa+αb xFb并结合颜色给出一般波特达夫方程co=αs xFaxCs+αb xFbxCb其中:co是输出颜色预先乘以输出α[0<=co<=1]αs是信号源的覆盖范围Fa是由操作者定义的,控制信号源的包含Cs是信号源的颜色(未乘以α)。αb是目的地的覆盖范围Fb由操作者定义,控制目的地的包含范围Cb是目的地的颜色(不乘以alpha)。

观察上文中的“pre-multiplied”,可以发现——

输出的颜色(co):是与Alpha进行预乘后的值(is the output color pre-multiplied with the output alpha)。因它是预乘值,为了转为Html5规范的位图颜色值,得再做一次“预乘值转非预乘值”的转换。源或背景的颜色(cs、cb):是非预乘的值(not multiplied by alpha)。因它是非预乘值,可直接使用Html5的位图颜色值。

Fa、Fb是Compositing类合成模式的系数。靠调整Fa、Fb的取值,构造了这12种“The Porter Duff Compositing Operators”。

2.2.2 “Source Over”运算模式的分析

“Source Over”是最常用的混合模式,现在以它为例来说明“Porter Duff公式”(the general Porter Duff equation)的用法。

摘录该文档的“9.1.4. Source Over”——

9.1.4.SourceOverSourceisplaced over the destination.example of porter duff source overFa=1;Fb=1αsco=αs xCs+αb xCbx(1αs)αo=αs+αb x(1αs)

co的计算公式是这样得到的——

将“Fa=1;Fb=1αs”带入“PorterDuff公式”(the generalPorterDuffequation)后:co=αs xFaxCs+αb xFbxCb=αs x(1)xCs+αb x(1αs)xCb=αs xCs+αb xCbx(1αs)

将上述co计算公式,与“5.1 Simple alpha compositing”里的公式进行对比,会发现它们是同一个公式。

co=Csxαs+Cbxαb x(1-αs)

即“Source Over”就是“Simple alpha compositing”(简单Alpha合成)。

2.2.3 演示页面是怎样显示“Source Over”的详细计算过程的

上一篇文章“用于分析26种画布合成模式(globalCompositeOperation)的演示页面”里,说到了该演示页面支持显示“点击像素的当前合成模式详细计算过程”。现在来说明一下演示页面是怎么实现的。

首先来看函数调用流程——

canvas_mousedown、canvas_mousemove事件里,会调用 showClickInfo。showClickInfo 获取点击的像素值,随后调用 getInfoByComposite,最后进行展示。getInfoByComposite 函数负责获取详细计算过程。

getInfoByComposite里与“Source Over”合成模式相关的代码,摘录如下:

/** Get info by composite detail.** @param {String} compositeMode The composite mode. From `Context.globalCompositeOperation` .* @param {Array} dataD The destination pixel value (RGBA bytes).* @param {Array} dataS The source pixel value (RGBA bytes).* @return {String} Returns color info.*/functiongetInfoByComposite(compositeMode,dataD,dataS){constdigits=3;constALL_CHANNELS=4;constCOLOR_CHANNELS=3;constALPHA_INDEX=COLOR_CHANNELS;constcolorNames=["R","G","B","A"];letmsg="compositeMode:\t"+compositeMode;letfD=toFloatColor(dataD);letfS=toFloatColor(dataS);letfO=newArray(ALL_CHANNELS);letAb=fD[ALPHA_INDEX];// background(destination) alpha.letAs=fS[ALPHA_INDEX];// source alpha.letAbStr=Ab.toFixed(digits);letAsStr=As.toFixed(digits);letinfo;leti;letshowOut=false;if("source-over"==compositeMode){msg+="\n\tFa = 1; Fb = 1 - As"+";\tCo = As * Cs + Ab * Cb * (1 - As)"+";\tAo = As + Ab * (1 - As)";showOut=true;for(i=0;i<COLOR_CHANNELS;++i){fO[i]=As*fS[i]+Ab*fD[i]*(1-As);letname=colorNames[i];msg+=`\n${name}o = As * ${name}s + Ab * ${name}b * (1 - As) = ${AsStr} * ${fS[i].toFixed(digits)} + ${AbStr} * ${fD[i].toFixed(digits)} * (1 - ${AsStr}) = ${fO[i].toFixed(digits)}`;}i=ALPHA_INDEX;fO[i]=As+Ab*(1-As);msg+=`\nAo = As + Ab * (1 - As) = ${AsStr} + ${AbStr} * (1 - ${AsStr}) = ${fO[i].toFixed(digits)}`;}if(showOut){letdataO=fromFloatColor(fO);letinfoO=getInfoByColorBytes(dataO);msg+="\nPremultiplie:"+infoO;letfW=alphaPremultiplieToStraight(fO);letdataW=fromFloatColor(fW);letinfoW=getInfoByColorBytes(dataW);msg+="\nOutput : "+infoW;}returnmsg;}

上面的代码比较简单,主要内容在2个if语句中——

compositeMode的if:用于实现“Source Over”的计算处理。首先将运算公式拼接到msg字符串里,随后用for循环里按公式处理R、G、B这3个颜色通道的计算,最后按公式处理A通道的计算。因计算结果是预乘的,于是设置showOut变量为true,统一由最后的if语句来展示计算结果。showOut的if:统一展示计算结果。首先展示直接的运算结果,它是预乘(Premultiplie)的值;随后做一次“预乘值转非预乘值”转换(alphaPremultiplieToStraight),再进行展示,此时得到是Html5画布里的颜色值。

补充说明——

为了方便运算,dataD, dataS是字节数组。它是一个长度为4的数组,分别为 R、G、B、A 分量的字节值,每个分量的值在 [0,255] 范围内。因文档上的公式都是用归一化浮点颜色值的,于是调用了toFloatColor函数,将dataD, dataS,转为了浮点颜色值 fD、fS。浮点颜色值是一个长度为4数组,分别为 R、G、B、A 分量的浮点值,每个分量的值在 [0,1] 范围内。fromFloatColor用于将浮点颜色值,转为RGBA整数颜色值。getInfoByColorBytes用于从RGBA整数颜色值得到颜色的详细说明。格式为“RGBA、Byte、#rrggbbaa、hsl、Pos”,即分别为“归一化的RGBA值、各分量的字节值、十六进制表示的颜色值、hsl格式的颜色值”。如“RGBA(0.357, 0.106, 0.427, 0.875), Byte(91, 27, 109, 223), #5b1b6ddf, hsl(287, 0.603, 0.267)”。alphaPremultiplieToStraight用于将预乘值,转为直通(Straight)值,即非预乘值。

2.3 Blending类合成模式的算法(10 Blending)

Compositing类合成模式(The Porter Duff Compositing Operators)偏重于原图像绘制到目标(背景)图像时的几何关系,而Blending类合成模式与此不同。Blending类合成模式里有2个关键步骤,先通过一个混合函数(B(Cb, Cs))将源与目标(背景)的颜色进行混合,再将“混合结果”的颜色进行“简单Alpha合成”运算,绘制到目标图像上。

2.3.1 第1步:混合函数处理

摘录——

10.BlendingBlendingisthe aspect of compositing that calculates the mixing of colorswherethe source elementandbackdrop overlap.Conceptually,the colorsinthe source element are blendedinplacewiththe backdrop.Afterblending,the modified source elementiscompositedwiththe backdrop.Inpractice,thisisusually all performedinone step.Theblending calculations mustnotusepre-multiplied color values.The"mixing"formulaisdefinedas:Cm=B(Cb,Cs)with:Cm:the result color after blendingB:the formula that does the blendingCb:the backdrop colorCs:the source colorTheresult of the mixing formula must be clamped to the minimumandmaximum values of the color range.

中文翻译——

10.混合混合是合成的一个方面,在源元素和背景重叠的地方计算颜色的混合。从概念上讲,源元素的颜色是与背景混合在一起的。混合后,修改后的源元素与背景合成。在实践中,这通常是在一个步骤中完成的。混合的计算不使用预乘的颜色值。混合"公式定义为:Cm = B(Cb, Cs)其中:Cm:混合后的结果颜色B:进行混合的公式Cb:背景色Cs:源色混合公式的结果必须限制在颜色范围的最小值和最大值中。

除了混合函数的概念外,这一段重点是“混合的计算不使用预乘的颜色值”。即源、背景颜色值均是“非预乘”的,与Html5的画布位图一致。其次提到对于混合函数的计算结果,需将它限制在颜色范围内,因为有时运算结果会超出范围。对于归一化的浮点颜色值来说,范围是 [0,1] 。

2.3.2 第2步:计算混合结果

摘录——

Theresult of the mixingfunctionismodulatedbythe backdrop alpha.A fully opaque backdrop allows the mixingfunctionto be fully realized.A transparent backdrop will cause thefinalresult to be a weighted average between the source colorandmixed colorwiththe weight controlledbythe backdrop alpha.Thevalue of thenewcolor becomes:Cr=(1-αb)xCs+αb x B(Cb,Cs)with:Cr:the result colorB:the formula that does the blendingCs:the source colorCb:the backdrop colorαb:the backdrop alpha

中文翻译——

混合功能的结果是由背景的α值来调制的。一个完全不透明的背景允许完全实现混合功能。一个透明的背景会导致最终的结果是源色和混合色之间的加权平均,其权重由背景的alpha控制。新颜色的值变成了。Cr=(1-αb)xCs+αb x B(Cb,Cs)其中:Cr:结果颜色B:进行混合的公式Cs:源色Cb:背景色αb:背景的阿尔法

单看公式,这一部分是比较好懂的,就是使用αb(背景Alpha值)对“B(Cb, Cs)函数运算结果 与 Cs(源颜色)进行Alpha插值”。但是这一部分的意义不止如此,后面会详细说明。

2.3.3 第3步:使用简单Alpha合成

摘录——

EXAMPLE12example of blendingwithopacityThisexample has a red rectanglewitha blending mode thatisplaced on top of asetof green rectangles that have different levels of opacity.Notehow the top rectangle shifts more toward redasthe opacity of the backdrop gets smaller.Note:Thefollowing formula gives the color valueinthe areawherethe sourceandbackdrop intersectsandthencompositeswiththe specifiedPorterDuffcompositing formula.Forsimple alpha blending,the formula thus becomes:simple alpha compositing:co=cs+cb x(1-αs)writtenasnon-premultiplied:αo xCo=αs xCs+(1-αs)xαb xCbnow substitute the result of blendingforCs:αo xCo=αs x((1-αb)xCs+αb x B(Cb,Cs))+(1-αs)xαb xCb=αs x(1-αb)xCs+αs xαb x B(Cb,Cs)+(1-αs)xαb xCb

中文翻译——

示例12用不透明度进行混合的例子这个例子有一个具有混合模式的红色矩形,它被放置在一组具有不同不透明度的绿色矩形的上面。请注意,当背景的不透明度变小时,顶部的矩形是如何向红色转移的。注意:下面的公式给出了源和背景相交的区域的颜色值,然后与指定的PorterDuff合成公式进行合成。对于简单的alpha混合,公式因此变为:简单的alpha合成:co=cs+cb x(1-αs)写成非预乘:αo xCo=αs xCs+(1-αs)xαb xCb现在用混合后的结果代替Csαo xCo=αs x((1-αb)xCs+αb x B(Cb,Cs))+(1-αs)xαb xCb=αs x(1-αb)xCs+αs xαb x B(Cb,Cs)+(1-αs)xαb xCb

这一步非常关键,但该文档里写的太简略。导致很容易引起误会。首先这里未加说明的引用了“预乘版的简单Alpha合成”,随后又简单的演示了“写成非预乘”。缺少详细说明,这对“预乘”概念不熟的人来说,很容易弄晕。更易引起误会的是“现在用混合后的结果代替Cs”的公式。“混合后的结果”(the result of blending)很容易被误会为第1步“B(Cb, Cs)”函数的计算结果,但它其实是第2步“Cr”(the result color)的值。这里“result”并不是指最终结果,而仅是指第2步的结果。且最后变换得到的式子还不够实用。B(Cb, Cs)这样的函数运算可移到最右侧,且“(1 - x)”这样的运算可挪到每个子项的右侧,这能使公式看起来更清晰.

现在来对上面公式变换补充说明——

引用预乘版简单的alpha合成公式:co=cs+cb x(1-αs)乘以各自的Alpha后,便是非预乘版公式:αo xCo=αs xCs+(1-αs)xαb xCb现在用混合后的结果(Cr)代替Csαo xCo=αs xCr+(1-αs)xαb xCb=αs x((1-αb)xCs+αb x B(Cb,Cs))+(1-αs)xαb xCb=αs x(1-αb)xCs+αs xαb x B(Cb,Cs)+(1-αs)xαb xCb=αs xCsx(1-αb)+αb xCbx(1-αs)+αs xαb x B(Cb,Cs)

这个最后得到的公式,看起来是非常整齐的。

2.3.4 如何计算Alpha通道

“10. Blending”这一章还遗漏一项关键内容——没有明确提到如何计算Alpha通道。

既然这一章提到了“简单的 alpha 合成”,那么Alpha通道的计算可能是与“简单的 alpha 合成”一样的,即——

αo=αs+αb x(1αs)

2.3.5 与Android公式的对比

Android的图像合成模式,用的是PorterDuff.Mode枚举。从名字上来看,它与“Porter Duff”提出的图像合成模式有关。但该枚举在不仅包含了Compositing类合成模式(PorterDuff.Mode枚举值 0~11),且包含了Blending类合成模式(PorterDuff.Mode枚举值 12~17)。PorterDuff.Mode枚举的说明里,每一个枚举值都给出了公式缩写。其中与“2.3.3 第3步:使用简单Alpha合成”最相像的,是DARKEN的公式,摘录如下——

[Sa+Da-Sa*Da,Sc*(1-Da)+Dc*(1-Sa)+min(Sc,Dc)]

Android公式由2个式子组成,前者(Sa + Da - SaDa)是Alpha通道的公式,后者(Sc(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc))是颜色通道的公式。Android公式使用了不同的缩写,且默认使用了预乘,导致初看起来有些不像,但其实是非常相像的。

先看Alpha通道,进行缩写替换,用“αs”代替“Sa”、“αb”代替“Da”——

Sa+Da-Sa*Da=αs+αb-αsb=αs+1*αb-αsb=αs+αb*(1-αs)

可发现它与“2.3.4 如何计算Alpha通道”的公式是相同的。

然后看颜色通道的公式。因——

Sc就是预乘的源颜色值,故它相当于w3c公式里的“αs x Cs”。Dc就是预乘的目标颜色值,故它相当于w3c公式里的“αb x Cb”。

代入颜色通道的公式后——

Sc*(1-Da)+Dc*(1-Sa)+min(Sc,Dc)=αs xCsx(1-αb)+αb xCbx(1-αs)+min(Sc,Dc)

此时便会发现它与“第3步:使用简单Alpha合成”的公式非常相似。摘录——

αo xCo=αs xCsx(1-αb)+αb xCbx(1-αs)+αs xαb x B(Cb,Cs)

“min(Sc, Dc)”可看作混合函数处理(B(Cb, Cs))。但细节上有些对不上,“min(αb x Cb, αs x Cs)”与“αs x αb x min(Cb, Cs)”的计算结果是不同的。且Android的Blending类合成模式(PorterDuff.Mode枚举值 12~17)中,很多模式的Alpha通道计算公式不同。如MULTIPLY,Alpha公式为“Sa + Da - Sa*Da”。而w3c的Blending类合成模式,Alpha公式均是相同的。

为了便于分析这些差别,我的 演示页面 对于Blending类合成模式,会分别给出w3c与Android的计算过程。例如对于darken模式,代码为——

}if("darken"==compositeMode){msg+="\n\tB(Cb, Cs) = min(Cb, Cs)";showOut=true;for(i=0;i<COLOR_CHANNELS;++i){letname=colorNames[i];letCs=fS[i];letCb=fD[i];letCm=Math.min(Cb,Cs);fO[i]=As*Cs*(1-Ab)+Ab*Cb*(1-As)+As*Ab*Cm;msg+=`\n${name}m = min(${name}b, ${name}s) = min(${Cb.toFixed(digits)}, ${Cs.toFixed(digits)}) = ${Cm.toFixed(digits)}`;msg+=`;\t${name}o = ${AsStr}*${Cs.toFixed(digits)} * (1 - ${AbStr}) + ${AbStr}*${Cb.toFixed(digits)} * (1 - ${AsStr}) + ${AsStr} * ${AbStr} * ${Cm.toFixed(digits)} = ${fO[i].toFixed(digits)}`;}i=ALPHA_INDEX;fO[i]=As+Ab*(1-As);msg+=`\nAo = As + Ab * (1 - As) = ${AsStr} + ${AbStr} * (1 - ${AsStr}) = ${fO[i].toFixed(digits)}`;info=getInfoByColorBytes(fromFloatColor(fO));msg+="\nPremultiplie:"+info;letfW=alphaPremultiplieToStraight(fO);info=getInfoByColorBytes(fromFloatColor(fW));msg+="\nOutput : "+info;// Android.msg+="\n\tAndroid: [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)]";fD=alphaStraightToPremultiplie(fD);fS=alphaStraightToPremultiplie(fS);for(i=0;i<COLOR_CHANNELS;++i){letname=colorNames[i];letSc=fS[i];letDc=fD[i];fO[i]=Sc*(1-Da)+Dc*(1-Sa)+Math.min(Sc,Dc);msg+=`\n${name}o = S${name}*(1 - Da) + D${name}*(1 - Sa) + min(S${name}, D${name}) = ${fS[i].toFixed(digits)}*(1 - ${DaStr}) + ${fD[i].toFixed(digits)}*(1 - ${SaStr}) + min(${fS[i].toFixed(digits)}, ${fD[i].toFixed(digits)}) = ${fO[i].toFixed(digits)}`;}i=ALPHA_INDEX;fO[i]=Sa+Da-Sa*Da;msg+=`\nAo = Sa + Da - Sa * Da = ${SaStr} + ${DaStr} - ${SaStr} * ${DaStr} = ${fO[i].toFixed(digits)}`;}

三、尾声

源码地址:https://github.com/zyl910/zhtml5info/blob/master/src/canvas/CanvasComposite.htm

参考文献

W3C《Compositing and Blending Level 1》. https://www.w3.org/TR/compositing-1/zyl910《[Html5] 用于分析26种画布合成模式(globalCompositeOperation)的演示页面》. https://www.cnblogs.com/zyl910/p/Html5_CanvasComposite_demo.htmlPorter, Thomas; Duff, Tom (July 1984). 《Compositing Digital Images》 (PDF). SIGGRAPH Computer Graphics. http://graphics.pixar.com/library/Compositing/paper.pdfMDN《CanvasRenderingContext2D.globalCompositeOperation》. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperationAndroid《PorterDuff.Mode》. http://docs.52im.net/extend/docs/api/android-50/reference/android/graphics/PorterDuff.Mode.html如果时光不来《图像合成(一)- PorterDuff.Mode》. https://www.jianshu.com/p/ee407e7093cd