[Html5] 徹底搞懂畫布合成模式(globalCompositeOperation)的計算公式

来源:https://www.cnblogs.com/zyl910/archive/2022/08/07/Html5_CanvasComposite_formula.html
-Advertisement-
Play Games

有人相愛,有人夜裡開車看海,我是leetcode第一題都做不出來 題目 給定一個整數數組 nums 和一個整數目標值 target,請你在該數組中找出 和為目標值 target 的那 兩個 整數,並返回它們的數組下標。 你可以假設每種輸入只會對應一個答案。但是,數組中同一個元素在答案里不能重覆出現。 ...


作者: 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)的演示頁面”里,說到了該演示頁面支持顯示“點擊像素的當前合成模式詳細計算過程”。現在來說明一下演示頁面是怎麼實現的。

首先來看函數調用流程——

  1. canvas_mousedown、canvas_mousemove事件里,會調用 showClickInfo。
  2. showClickInfo 獲取點擊的像素值,隨後調用 getInfoByComposite,最後進行展示。
  3. 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語句中——

  1. compositeMode的if:用於實現“Source Over”的計算處理。首先將運算公式拼接到msg字元串里,隨後用for迴圈里按公式處理R、G、B這3個顏色通道的計算,最後按公式處理A通道的計算。因計算結果是預乘的,於是設置showOut變數為true,統一由最後的if語句來展示計算結果。
  2. 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

參考文獻

作者:zyl910 出處:http://www.cnblogs.com/zyl910/ 版權聲明:自由轉載-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0.
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 從零開始搭建基於 ABP Framework 分層架構解決方案,快速集成框架內置應用模塊。探索基於 ABP Framework 極速開發的最佳路徑,構建一個模塊完備、可開發、可調試、可發佈和部署的分層架構解決方案。 ...
  • 一、前言 之前分享過一期關於DrawingVisual來繪製高性能曲線的博客,今天再分享一篇通過另一種方式來繪製高性能曲線的方法,也就是通過WriteableBitmap的方式;具體的一些細節這裡就不啰嗦了,同樣是局部繪製的思想,滾動條拖動到哪裡,就只繪製那一部分的曲線,直接貼代碼;(該程式在英特爾 ...
  • 規則,點擊投籃目標點,就會有一個球沿著相關拋物線,然後,判斷是否進入籃子里,其實就是一個矩形,直接是按照碰撞檢測來的,碰到就算進去了,對其增加了一個分數統計等功能。 ...
  • 1、await和.result/ .getwaiter() .getresult()的區別 await:Task.Run裡面的邏輯是新開的線程去執行的,await Task.Run後面邏輯都在新開的線程去執行。 private async void MainWindow_Loaded(object ...
  • 在智慧工廠領域,智慧城市領域,都需要對設備進行監控。比如工廠需要對周圍環境溫度、濕度、氣壓、電壓,燈的開關進行監控。這時候就需要物聯網平臺來進行管理。 在智慧工廠領域,寶馬集團通過英偉達的Omniverse平臺在電腦中創建數字孿生工廠,併在數字孿生工廠中進行改變生產線配置、工人動線、倉儲管理等實驗 ...
  • 前言 在進行某些爬蟲任務的時候,我們經常會遇到僅用Http協議難以攻破的情況,比如協議中帶有加密參數,破解需要花費大量時間,那這時候就會用Selenium去模擬瀏覽器進行頁面上的元素抓取 大多數情況下我們用Selenium只是爬取一下頁面上可見的元素信息或者做一些模擬人工的操作,但頁面可見元素的數據 ...
  • 需求背景: 近日,在安裝某軟體過程,發現在安裝過程需要輸入一些信息才能繼續下一步操作,在機器數量較少情況下,我們可以單台登錄上去完成安裝操作,但當機器數量超過一定時,如果再手動登錄操作,就會產生大量重覆性操作,既不能帶來有效學習能力提升,同時也會極大產生不確定性,引發工作效率下降,那麼如何自動化完成 ...
  • getIRC-Best IRC Client for mac是一款實用的IRC客戶端,它由各種獨立的 IRC 伺服器網路(或“網路”)組成,這些機器允許用戶連接到 IRC。 詳情:getIRC-Best IRC Client for mac(IRC客戶端) 簡單介紹 macOS 上的 Interne ...
一周排行
    -Advertisement-
    Play Games
  • 概述:本文代碼示例演示瞭如何在WPF中使用LiveCharts庫創建動態條形圖。通過創建數據模型、ViewModel和在XAML中使用`CartesianChart`控制項,你可以輕鬆實現圖表的數據綁定和動態更新。我將通過清晰的步驟指南包括詳細的中文註釋,幫助你快速理解並應用這一功能。 先上效果: 在 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • openGauss(GaussDB ) openGauss是一款全面友好開放,攜手伙伴共同打造的企業級開源關係型資料庫。openGauss採用木蘭寬鬆許可證v2發行,提供面向多核架構的極致性能、全鏈路的業務、數據安全、基於AI的調優和高效運維的能力。openGauss深度融合華為在資料庫領域多年的研 ...
  • 概述:本示例演示了在WPF應用程式中實現多語言支持的詳細步驟。通過資源字典和數據綁定,以及使用語言管理器類,應用程式能夠在運行時動態切換語言。這種方法使得多語言支持更加靈活,便於維護,同時提供清晰的代碼結構。 在WPF中實現多語言的一種常見方法是使用資源字典和數據綁定。以下是一個詳細的步驟和示例源代 ...
  • 描述(做一個簡單的記錄): 事件(event)的本質是一個委托;(聲明一個事件: public event TestDelegate eventTest;) 委托(delegate)可以理解為一個符合某種簽名的方法類型;比如:TestDelegate委托的返回數據類型為string,參數為 int和 ...
  • 1、AOT適合場景 Aot適合工具類型的項目使用,優點禁止反編 ,第一次啟動快,業務型項目或者反射多的項目不適合用AOT AOT更新記錄: 實實在在經過實踐的AOT ORM 5.1.4.117 +支持AOT 5.1.4.123 +支持CodeFirst和非同步方法 5.1.4.129-preview1 ...
  • 總說周知,UWP 是運行在沙盒裡面的,所有許可權都有嚴格限制,和沙盒外交互也需要特殊的通道,所以從根本杜絕了 UWP 毒瘤的存在。但是實際上 UWP 只是一個應用模型,本身是沒有什麼許可權管理的,許可權管理全靠 App Container 沙盒控制,如果我們脫離了這個沙盒,UWP 就會放飛自我了。那麼有沒... ...
  • 目錄條款17:讓介面容易被正確使用,不易被誤用(Make interfaces easy to use correctly and hard to use incorrectly)限制類型和值規定能做和不能做的事提供行為一致的介面條款19:設計class猶如設計type(Treat class de ...
  • title: 從零開始:Django項目的創建與配置指南 date: 2024/5/2 18:29:33 updated: 2024/5/2 18:29:33 categories: 後端開發 tags: Django WebDev Python ORM Security Deployment Op ...
  • 1、BOM對象 BOM:Broswer object model,即瀏覽器提供我們開發者在javascript用於操作瀏覽器的對象。 1.1、window對象 視窗方法 // BOM Browser object model 瀏覽器對象模型 // js中最大的一個對象.整個瀏覽器視窗出現的所有東西都 ...