作者: zyl910
一、緣由
上一篇文章“用于分析26種畫布合成模式(globalCompositeOperation)的演示頁面”給出了便于測驗的演示頁面,現在探究一下合成模式的計算公式,
在網上搜索了一下,發現W3C《Compositing and Blending Level 1》對合成模式的公式說的最詳細,于是仔細閱讀了該檔案,
該檔案的篇幅比較長,且是英文版的,看起來比較吃力,且有些細節寫的比較簡略,若忽略了那些細節,可能會導致構造的公式不正確、計算結果不符,
于是整理了一下我的心得,撰寫了此文,
二、《Compositing and Blending Level 1》閱讀心得
對于合成模式來說,最重要的內容在該檔案的這幾個章節——
5.1 Simple alpha compositing
9 Advanced compositing features
10 Blending
“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”里,首先說明了如何計算顏色分量,摘錄——
The formula for simple alpha compositing is
co = Cs x αs + Cb x αb x (1 - αs)
Where
co: the premultiplied pixel value after compositing
Cs: the color value of the source graphic element being composited
αs: the alpha value of the source graphic element being composited
Cb: the color value of the backdrop
αb: the alpha value of the backdrop
Note: All values are between 0 and 1 inclusive.
The pixel value after compositing (co) is given by adding the contributions from the source graphic element [Cs x αs] and the backdrop [Cb x αb x (1 - αs)]. For both the graphic element and the backdrop, the color values are multiplied by the alpha to determine the amount of color that contributes. With zero alpha meaning that the color does not contribute and partial alpha means that some percentage of the color contributes. The contribution of the backdrop is further reduced based on the opacity of the graphic element. Conceptually, (1 - αs) of the backdrop shows through the graphic element, meaning that if the graphic element is fully opaque (αs=1) then no backdrop shows through.
中文翻譯——
5.1,簡單的 alpha 合成
簡單 alpha 合成的公式是
co = Cs x αs + Cb x αb x (1 - αs)
其中
co:合成后的預乘像素值
cs:正在合成的源圖形元素的顏色值
αs:正在合成的源圖形元素的 alpha 值
Cb:背景的顏色值
αb:背景的 alpha 值
注意:所有值都介于 0 和 1 之間,
合成后的像素值 (co) 由源圖形元素 [Cs x αs] 和背景 [Cb x α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(不透明度)分量,摘錄——
The simple alpha compositing formula listed above gives a resultant color which is the result of the weighted average of the backdrop color and graphic element color, with the weighting determined by the backdrop and graphic element alphas. The resultant alpha value of the composite is simply the sum of the contributed alpha of the composited elements. The formula for the resultant alpha of the composite is
α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 value for the color and opacity. The pre-multiplied value is given by
cs = Cs x αs
with
cs: the pre-multiplied value
Cs: the color value
αs: the alpha value
Thus the formula for simple alpha compositing using pre-multiplied values becomes
co = cs + cb x (1 - αs)
To extract the color component of a pre-multiplied value, the formula is reversed:
Co = co / αo
中文翻譯——
通常,存盤顏色和不透明度的預乘值會更有效,預乘法的值由以下公式給出
cs = Cs x αs
其中
cs:預乘值
Cs:顏色值
αs:alpha值
因此,使用預乘值進行簡單 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 = Cs x αs + Cb x α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. The Porter Duff Compositing Operators
The landmark paper by Thomas Porter and Tom Duff, who worked for Lucasfilm, defined the algebra of compositing and developed the twelve "Porter Duff" operators. These operators control the results of mixing the four sub-pixel regions formed by the overlapping of graphical objects that have an alpha or pixel coverage channel/value. The operators use all practical combinations of the four regions.
There are 12 basic Porter Duff operators, satisfying all possible combinations of source and destination.
From the geometric representation of each operator, the contribution of each shape can be seen to be expressed as a fraction of the total coverage of the output. For example, in source over, the possible contribution of source is full (1) and the possible contribution of destination is whatever is remaining (1 – αs). This is modified by the coverage of source and destination to give the equation for the final coverage of the pixel:
αo = αs x 1 + αb x (1 – αs)
The fractional terms Fa (1 in this example) and Fb (1 – αs in this example) are defined for each operator and specify the fraction of the shapes that may contribute to the final pixel value. The general form of the equation for coverage is:
αs x Fa + αb x Fb
and incorporating color gives the general Porter Duff equation
co = αs x Fa x Cs + αb x Fb x Cb
Where:
co is the output color pre-multiplied with the output alpha [0 <= co <= 1]
αs is the coverage of the source Fa is defined by the operator and controls inclusion of the source Cs is the color of the source (not multiplied by alpha)
αb is the coverage of the destination Fb is defined by the operator and controls inclusion of the destination Cb is the color of the destination (not multiplied by alpha)
中文翻譯——
9.1. 波特-達夫合成算子
為盧卡斯影業作業的托馬斯-波特和湯姆-達夫發表了一篇具有里程碑意義的論文,定義了合成的代數并開發了12個 "波特-達夫 "算子,這些算子控制著由具有阿爾法或像素覆寫通道/值的圖形物件的重疊所形成的四個子像素區域的混合結果,這些算子使用這四個區域的所有實際組合,
有12個基本的波特-達夫算子,滿足源和目的的所有可能組合,
從每個算子的幾何表示法來看,每個形狀的貢獻可以被看作是輸出的總覆寫率的一部分來表示,例如,在源超過,源的可能貢獻是完全的(1),目的地的可能貢獻是任何剩余的(1-αs),這是由源和目的地的覆寫率修改的,從而得到像素的最終覆寫率的方程式,
αo = αs x 1 + αb x (1 - αs)
分數項Fa(本例中為1)和Fb(本例中為1-αs)是為每個算子定義的,并指定了可能對最終像素值有貢獻的形狀的分數,覆寫率方程的一般形式是,
αs x Fa + αb x Fb
并結合顏色給出一般波特達夫方程
co = αs x Fa x Cs + αb x Fb x Cb
其中:
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. Source Over
Source is placed over the destination.
example of porter duff source over
Fa = 1; Fb = 1 – αs
co = αs x Cs + αb x Cb x (1 – αs)
αo = αs + αb x (1 – αs)
co的計算公式是這樣得到的——
將“Fa = 1; Fb = 1 – αs”帶入“Porter Duff公式”(the general Porter Duff equation)后:
co = αs x Fa x Cs + αb x Fb x Cb
= αs x (1) x Cs + αb x (1 – αs) x Cb
= αs x Cs + αb x Cb x (1 – αs)
將上述co計算公式,與“5.1 Simple alpha compositing”里的公式進行對比,會發現它們是同一個公式,
co = Cs x αs + Cb x α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.
*/
function getInfoByComposite(compositeMode, dataD, dataS) {
const digits = 3;
const ALL_CHANNELS = 4;
const COLOR_CHANNELS = 3;
const ALPHA_INDEX = COLOR_CHANNELS;
const colorNames = ["R", "G", "B", "A"];
let msg = "compositeMode:\t" + compositeMode;
let fD = toFloatColor(dataD);
let fS = toFloatColor(dataS);
let fO = new Array(ALL_CHANNELS);
let Ab = fD[ALPHA_INDEX]; // background(destination) alpha.
let As = fS[ALPHA_INDEX]; // source alpha.
let AbStr = Ab.toFixed(digits);
let AsStr = As.toFixed(digits);
let info;
let i;
let showOut = 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);
let name = 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) {
let dataO = fromFloatColor(fO);
let infoO = getInfoByColorBytes(dataO);
msg += "\nPremultiplie:" + infoO;
let fW = alphaPremultiplieToStraight(fO);
let dataW = fromFloatColor(fW);
let infoW = getInfoByColorBytes(dataW);
msg += "\nOutput : " + infoW;
}
return msg;
}
上面的代碼比較簡單,主要內容在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. Blending
Blending is the aspect of compositing that calculates the mixing of colors where the source element and backdrop overlap.
Conceptually, the colors in the source element are blended in place with the backdrop. After blending, the modified source element is composited with the backdrop. In practice, this is usually all performed in one step.
The blending calculations must not use pre-multiplied color values.
The "mixing" formula is defined as:
Cm = B(Cb, Cs)
with:
Cm: the result color after blending
B: the formula that does the blending
Cb: the backdrop color
Cs: the source color
The result of the mixing formula must be clamped to the minimum and maximum values of the color range.
中文翻譯——
10. 混合
混合是合成的一個方面,在源元素和背景重疊的地方計算顏色的混合,
從概念上講,源元素的顏色是與背景混合在一起的,混合后,修改后的源元素與背景合成,在實踐中,這通常是在一個步驟中完成的,
混合的計算不使用預乘的顏色值,
混合 "公式定義為:
Cm = B(Cb, Cs)
其中:
Cm:混合后的結果顏色
B:進行混合的公式
Cb:背景色
Cs:源色
混合公式的結果必須限制在顏色范圍的最小值和最大值中,
除了混合函式的概念外,這一段重點是“混合的計算不使用預乘的顏色值”,即源、背景顏色值均是“非預乘”的,與Html5的畫布位圖一致,
其次提到對于混合函式的計算結果,需將它限制在顏色范圍內,因為有時運算結果會超出范圍,對于歸一化的浮點顏色值來說,范圍是 [0,1] ,
2.3.2 第2步:計算混合結果
摘錄——
The result of the mixing function is modulated by the backdrop alpha. A fully opaque backdrop allows the mixing function to be fully realized. A transparent backdrop will cause the final result to be a weighted average between the source color and mixed color with the weight controlled by the backdrop alpha. The value of the new color becomes:
Cr = (1 - αb) x Cs + αb x B(Cb, Cs)
with:
Cr: the result color
B: the formula that does the blending
Cs: the source color
Cb: the backdrop color
αb: the backdrop alpha
中文翻譯——
混合功能的結果是由背景的α值來調制的,一個完全不透明的背景允許完全實作混合功能,一個透明的背景會導致最終的結果是源色和混合色之間的加權平均,其權重由背景的alpha控制,新顏色的值變成了,
Cr = (1 - αb) x Cs + αb x B(Cb, Cs)
其中:
Cr:結果顏色
B:進行混合的公式
Cs:源色
Cb:背景色
αb:背景的阿爾法
單看公式,這一部分是比較好懂的,就是使用αb(背景Alpha值)對“B(Cb, Cs)函式運算結果 與 Cs(源顏色)進行Alpha插值”,
但是這一部分的意義不止如此,后面會詳細說明,
2.3.3 第3步:使用簡單Alpha合成
摘錄——
EXAMPLE 12
example of blending with opacity
This example has a red rectangle with a blending mode that is placed on top of a set of green rectangles that have different levels of opacity.
Note how the top rectangle shifts more toward red as the opacity of the backdrop gets smaller.
Note: The following formula gives the color value in the area where the source and backdrop intersects and then composites with the specified Porter Duff compositing formula. For simple alpha blending, the formula thus becomes:
simple alpha compositing:
co = cs + cb x (1 - αs)
written as non-premultiplied:
αo x Co = αs x Cs + (1 - αs) x αb x Cb
now substitute the result of blending for Cs:
αo x Co = αs x ((1 - αb) x Cs + αb x B(Cb, Cs)) + (1 - αs) x αb x Cb
= αs x (1 - αb) x Cs + αs x αb x B(Cb, Cs) + (1 - αs) x αb x Cb
中文翻譯——
示例 12
用不透明度進行混合的例子
這個例子有一個具有混合模式的紅色矩形,它被放置在一組具有不同不透明度的綠色矩形的上面,
請注意,當背景的不透明度變小時,頂部的矩形是如何向紅色轉移的,
注意:下面的公式給出了源和背景相交的區域的顏色值,然后與指定的 Porter Duff 合成公式進行合成,對于簡單的 alpha 混合,公式因此變為:
簡單的 alpha 合成:
co = cs + cb x (1 - αs)
寫成非預乘:
αo x Co = αs x Cs + (1 - αs) x αb x Cb
現在用混合后的結果代替Cs:
αo x Co = αs x ((1 - αb) x Cs + αb x B(Cb, Cs)) + (1 - αs) x αb x Cb
= αs x (1 - αb) x Cs + αs x αb x B(Cb, Cs) + (1 - αs) x αb x Cb
這一步非常關鍵,但該檔案里寫的太簡略,導致很容易引起誤會,
首先這里未加說明的參考了“預乘版的簡單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 x Co = αs x Cs + (1 - αs) x αb x Cb
現在用混合后的結果(Cr)代替Cs:
αo x Co = αs x Cr + (1 - αs) x αb x Cb
= αs x ((1 - αb) x Cs + αb x B(Cb, Cs)) + (1 - αs) x αb x Cb
= αs x (1 - αb) x Cs + αs x αb x B(Cb, Cs) + (1 - αs) x αb x Cb
= αs x Cs x (1 - αb) + αb x Cb x (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 - αs *αb
= αs + 1 * αb - αs *αb
= α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 x Cs x (1 - αb) + αb x Cb x (1 - αs) + min(Sc, Dc)
此時便會發現它與“第3步:使用簡單Alpha合成”的公式非常相似,摘錄——
αo x Co = αs x Cs x (1 - αb) + αb x Cb x (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) {
let name = colorNames[i];
let Cs = fS[i];
let Cb = fD[i];
let Cm = 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;
let fW = 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) {
let name = colorNames[i];
let Sc = fS[i];
let Dc = 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.html
- Porter, Thomas; Duff, Tom (July 1984). 《Compositing Digital Images》 (PDF). SIGGRAPH Computer Graphics. http://graphics.pixar.com/library/Compositing/paper.pdf
- MDN《CanvasRenderingContext2D.globalCompositeOperation》. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
- Android《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
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/501197.html
標籤:HTML5
上一篇:svg中畫半圓
下一篇:關于重繪和回流的決議
