用兩種RGB顏色對矩形進行線性漸變填充時,需要合適的算法計算各點的顏色,這樣纔不會出現中間過渡色,或者出現漸變填充不完整。而在增加從任意角度進行漸變後,情況似乎變得更加複雜。
又比如這樣:
這些都是色彩計算錯誤引起的。現在來看看正確的漸變圖,其中顏色和漸變角度和上面的一樣:
首先說明漸變角度,在本例中是以垂直向上爲0度,順時針增加到360度。
如45度偏轉漸變如下:
下邊貼出漸變色計算過程代碼,例子是在VC2010下做的,顏色的表示借用了windows的COLORREF:
/**
* 計算線性漸變色
* @param crBegin 前景色
* @param crEnd 漸變色
* @param degree 漸變角度,以垂直向上爲0度,順時針增加到360度
* @param width 矩形區域的寬度
* @param height 矩形區域的高度
* @param x 橫座標,在矩形區域中起點爲0,向右遞增
* @param y 縱座標,在矩形區域中起點爲0,向下遞增
* @return 計算後的線性漸變色
*/
COLORREF CalcLinearGradientColor(COLORREF crBegin, COLORREF crEnd, int degree, int width, int height, int x, int y)
{
/// 漸變高寬值
float fwdith = (float)width;
float fheight = (float)height;
/// 座標值
int posx = x;
int posy = y;
int gradientDegree = 0; ///< 漸變角度,以垂直向上爲0度,順時針增加到360度
/// 對不同角度使用了對稱變換和平移變換。顏色出現分割是角度不對;顏色漸變方向錯誤是座標不對
if( degree>=0 && degree<90 )
gradientDegree = degree;
else if( degree>90 && degree<=180 )
gradientDegree = degree-90;
else if( degree>180 && degree<=270 )
gradientDegree = degree-180;
else // if( degree>270 && degree<=360 )
gradientDegree = degree-270;
/// 當前座標值加1;若座標值=0,則在邊界上會出現純色
//posx += 1;
//posy += 1;
/// 角度轉爲弧度
float radian = gradientDegree*YY_PI/180;
/// 根據漸變角度重新計算高寬,以便能容納下整個圖像。
float newWdith = fwdith*(cos(radian)) + fheight*(sin(radian));
float newHeight = fwdith*(sin(radian)) + fheight*(cos(radian));
/// 將當前座標點轉換爲新的矩形下的座標點;此例只需縱座標。注意當角度偏轉爲反斜線時,須互換高寬
float newY = 0.0;
if(degree>=0&°ree<90)
newY = posy*cos(radian) + (fwdith-posx)*sin(radian);
else if(degree>=90&°ree<=180) {
float temp = newWdith;
newWdith = newHeight;
newHeight = temp;
newY = newHeight-(posx*cos(radian)+posy*sin(radian));
} else if(degree>180&°ree<=270)
newY = (fheight-posy)*cos(radian) + posx*sin(radian);
else { //if( degree>270 && degree<=360 )
float temp = newWdith;
newWdith = newHeight;
newHeight = temp;
newY = posx*cos(radian) + posy*sin(radian);
}
/// 計算漸變後的顏色
float fbegin=0.0; float fend = 0.0; // 起止顏色,須以float參與運算
float step = 0.0; // 漸變步長,以各種顏色分量進行計算
/// 計算漸變色
unsigned char rRed, rGreen, rBlue;
/// 紅
fbegin = (float)GetRValue(crBegin); fend = (float)GetRValue(crEnd);
step = (fend-fbegin)/newHeight;
rRed = (int)( fbegin+step*newY );
/// 綠
fbegin = (float)GetGValue(crBegin); fend = (float)GetGValue(crEnd);
step = (fend-fbegin)/newHeight;
rGreen = (int)( fbegin+step*newY );
/// 藍
fbegin = (float)GetBValue(crBegin); fend = (float)GetBValue(crEnd);
step = (fend-fbegin)/newHeight;
rBlue = (int)( fbegin+step*newY );
///// 透明度
//fbegin = (float)bAlpha; fend = (float)eAlpha;
//step = (fend-fbegin)/newHeight;
//rAlpha = (int)( fbegin+step*newY );
return RGB(rRed, rGreen, rBlue);
}
下面描述一下此例中線性漸變算法的過程以及數學依據,不感興趣的可直接跳到末尾下載代碼:
- 在漸變方向上做一個能包容當前矩形的新的矩形,新矩形與漸變線是垂直的。
- 根據當前矩形區域的寬和高以及漸變角度計算新矩形的寬和高
- 把當前矩形中的當前點的座標映射到新矩形中,此例中只用到了Y座標
- 從漸變線方向開始,從上往下進行垂直漸變
這樣,不管從什麼角度進行漸變,實際上都是好像是從上往下進行的漸變,如此一來,就容易理解了。
需注意的是漸變角度要分爲4個區域進行討論,分別如下:
圖示說明:
- w和h表示當前矩形的寬和高
- a表示漸變角度
- 帶箭頭的黑線表示了漸變角度和方向
- nw和nh表示新矩形的寬和高
- 黑點是用作分析的示例點,虛線表示它在當前矩形中的橫縱座標,紅色線表示它在新矩形中的橫縱坐
- 標記出的各個角是角度相同的角
另外特別需要注意的一點是各個漸變角度在實際計算時都將其範圍縮減到0~90度之間。
當漸變角度在0~90度之間時,如下圖所示:
2、當漸變角度在90~180度之間時,如下圖所示:
3、當漸變角度在180~270度之間時,如下圖所示:
4、當漸變角度在270~360度之間時,如下圖所示: