用VC 實現圖象漸顯和漸隱 (轉)

worldblog發表於2007-12-25
用VC 實現圖象漸顯和漸隱 (轉)[@more@]
作者: 周長發

摘 要 圖象的漸顯/漸隱被廣泛運用與圖象處理和多媒提娛樂。本文基於的調色盤動畫和時間碼技術設計了通用的圖象漸顯和漸隱演算法,並實現了其Visual C++編碼。

關鍵詞 漸顯、漸隱、調色盤、調色盤動畫、時間碼

圖象的漸顯/漸隱是十分重要的圖象效果,廣泛運用於圖象處理和多媒提娛樂軟體。漸顯/漸隱演算法設計的最大困難是速度控制,包括定時和改變圖象中各象素的顏色。如採用普通的全圖掃描演算法,則速度較慢,很難真正體現漸顯/漸隱效果。

利用Windows(3.x.95/98/NT)操作特殊的調色盤管理和時間碼定時機制能設計出有效的圖象漸顯/漸隱演算法。Windows提供一種被稱為調色盤動畫(palette animation)的顏色處理技術,它透過快速改變顏色調色盤中所選取的表項中的顏色能模擬顏色的變化。設定時間碼,定時該技術使圖象顏色漸變就能實現圖象的漸顯和漸隱。

一、調色盤動畫

在Visual C++中實現調色盤動畫依賴於MFC類庫提供的CPalette類和CDC類中的若干成員,其基本步驟如下:

呼叫CPalette::CreatePalette(LPLOGPALETTE lpLogPalette)函式建立邏輯調色盤,注意將引數LPLOGPALETTE所指向的各顏色表項結構的peFlags域設定為PC_RESERVED,以防止其它視窗同該調色盤匹配顏色。;
呼叫CDC::Palette和CDC::RealizePalette函式選擇和實現所建立的邏輯調色盤;
呼叫CPalette::AnimatePalette函式改變顏色,實現調色盤動畫;
動畫完成後應恢復系統調色盤。
CPalette::AnimatePalette是其中最關鍵的函式,其原型如下:

void AnimatePalette(

UINT nStartIndex, // 起始的表項號

UINT nNumEntries, // 變化的表項數

LPPALETTEENTRY lpPaletteColors ); // 邏輯調色盤表項指標

lpPaletteColors為指向PALETTEENTRY結構的指標,其中著邏輯調色盤將要的顏色資訊。PALETTEENTRY結構定義如下:

typedef struct tagPALETTEENTRY { // pe

BYTE peRed;

BYTE peGreen;

BYTE peBlue;

BYTE peFlags;

} PALETTEENTRY;

peRed、peGreen、peBlue分別表示邏輯調色盤項的R、G、B顏色分量值。peFlags 應被置為PC_RESERVED 。

nStartIndex為lpPaletteColors中將變化的起始表項號,nNumEntries 為lpPaletteColors中將變化的表項數。

二、時間碼定時

CWnd::SetTimer函式可設定一個系統時間碼,並指定每經過一定的時間間隔使Windows系統傳送一個WM_TIMER訊息到視窗的訊息佇列中。視窗在每當接收到相應的WM_TIMER訊息時做一定的處理,便實現了定時處理。

通常應在視窗的訊息迴圈中接受和處理WM_TIMER訊息,這樣將很難編制通用的定時操作。通用的定時操作應將定時處理封裝在一個函式中,而不與其它的程式碼糾纏在一起。筆者實現這一技術的技巧是,在迴圈操作中截獲視窗訊息,如訊息為指定的時間碼訊息,則進行定時處理;否則分發訊息給視窗訊息處理機制。如果定時操作已結束,則修改迴圈標誌,退出迴圈。具體的程式碼如下:

………………………………

// 設定時間碼,pWnd為處理定時操作的視窗指標

pWnd->SetTimer(0x100, uTimeOut, NULL);

// 遮蔽滑鼠操作,使定時操作不受影響

pWnd->SetCapture();

// 開始定時操作

BOOL bDone = FALSE;

MSG msg;

while (! bDone)

{

if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{

if (msg.message == WM_TIMER && msg. WParam == 0x100)

{

…………………..

定時操作程式碼

…………………..

// 如定時操作完成,則設定迴圈標誌,結束操作

if (定時操作完成)

bDone = TRUE;

}

::TranslateMessage(&msg);

::DispatchMessage(&msg);

}

}

// 釋放滑鼠

::ReleaseCapture();

// 刪除時間碼

pWnd->KillTimer(0x100);

…………………………..

函式PeekMessage截獲視窗訊息,TranslateMessage和DispatchMessage函式解釋和分發除指定時間碼訊息之外的所有訊息,以避免丟失訊息。

三、漸顯

漸顯就是將顯示顏色由黑色(RGB(0, 0, 0))逐漸變化為圖象各象素的顏色的過程。開始時呼叫CPalette::GetPaletteEntries函式儲存圖象調色盤的各邏輯表項資訊,然後呼叫CPalette::SetPaletteEntries函式將邏輯調色盤中各邏輯表項的peRed、peGreen、peBlue置為0,定時呼叫CPalette::AnimatePalette,每次將各邏輯表項的peRed、peGreen、peBlue值增加一個變化量,直到它們分別等於圖象邏輯調色盤中各邏輯表項的peRed、peGreen、peBlue值。

下面的函式FadeIn透過對調色盤顏色表項中的各顏色分量值先設為0,然後進行遞增,直到所有顏色值都恢復成原調色盤中顏色值來實現漸顯。

// 圖象漸顯效果

// 引數:

// pWnd – 顯示圖象的視窗

// pPal – 調色盤指標

// nDeta – 各顏色分量的減小量

// uTimeOut – 時間的變化量

void FadeIn(CWnd *pWnd, CPalette *pPal, int nDeta, UINT uTimeOut)

{

// 保留原來的調色盤顏色表項

int nTotalColors = pPal->GetEntryCount();

PALETTEENTRY PaletteColors0[256];

pPal->GetPaletteEntries(0, nTotalColors, PaletteColors0);

// 先將調色盤表項中各顏色分量置為0

PALETTEENTRY PaletteColors1[256];

for (int i=0; i
{

PaletteColors1[i].peRed = 0;

PaletteColors1[i].peGreen = 0;

PaletteColors1[i].peBlue = 0;

PaletteColors1[i].peFlags = PC_RESERVED;

}

pPal->SetPaletteEntries(0, nTotalColors, PaletteColors1);

pPal->AnimatePalette(0, nTotalColors, PaletteColors1);

// 設定時間碼

pWnd->SetTimer(0x100, uTimeOut, NULL);

// 開始漸顯

pWnd->SetCapture();

BOOL bDone = FALSE;

MSG msg;

while (! bDone)

{

if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{

if (msg.message == WM_TIMER && msg.wParam == 0x100)

{

CClientDC dc(pWnd);

CPalette *pOldPal = dc.SelectPalette(pPal, FALSE);

dc.RealizePalette();

// 遞增各顏色分量

PALETTEENTRY PaletteColors[256];

pPal->GetPaletteEntries(0, nTotalColors, PaletteColors);

BOOL bRedZero=FALSE;

BOOL bGreenZero=FALSE;

BOOL bBlueZero=FALSE;

for (int i=0; i
{

if (PaletteColors[i].peRed + nDeta <

PaletteColors0[i].peRed)

{

PaletteColors[i].peRed += nDeta;

bRedZero = FALSE;

}

else if (PaletteColors[i].peRed + 1 <

PaletteColors0[i].peRed)

{

PaletteColors[i].peRed++;

bRedZero = FALSE;

}

else

bRedZero = TRUE;

if (PaletteColors[i].peGreen + nDeta <

PaletteColors0[i].peGreen)

{

PaletteColors[i].peGreen += nDeta;

bGreenZero = FALSE;

}

else if (PaletteColors[i].peGreen + 1 <

PaletteColors0[i].peGreen)

{

PaletteColors[i].peGreen++;

bGreenZero = FALSE;

}

else

bGreenZero = TRUE;

if (PaletteColors[i].peBlue + nDeta <

PaletteColors0[i].peBlue)

{

PaletteColors[i].peBlue += nDeta;

bBlueZero = FALSE;

}

else if (PaletteColors[i].peBlue +1 <

PaletteColors0[i].peBlue)

{

PaletteColors[i].peBlue++;

bBlueZero = FALSE;

}

else

bBlueZero = TRUE;

}

// 直到恢復原始值結束

bDone = bRedZero && bGreenZero && bBlueZero;

// 使系統改變調色盤

pPal->AnimatePalette(0, nTotalColors, PaletteColors);

}

::TranslateMessage(&msg);

::DispatchMessage(&msg);

}

}

::ReleaseCapture();

pWnd->KillTimer(0x100);

// 恢復原始調色盤

pPal->SetPaletteEntries(0, nTotalColors, PaletteColors0);

pPal->AnimatePalette(0, nTotalColors, PaletteColors0);

}

四、漸隱

漸隱就是將顯示顏色由圖象各象素的顏色逐漸變化為黑色(RGB(0, 0, 0))的過程,即定時呼叫CPalette::AnimatePalette,每次將各邏輯表項的peRed、peGreen、peBlue值減小一個變化量,直到它們都為0。

下面的函式FadeOut透過對調色盤顏色表項中的各顏色分量值進行遞減,直到所有顏色值都變成0(即黑色)來實現漸隱。

// 圖象漸隱效果

// 引數:

// pWnd – 顯示圖象的視窗

// pPal – 調色盤指標

// nDeta – 各顏色分量的減小量

// uTimeOut – 時間的變化量

void FadeOut(CWnd *pWnd, CPalette *pPal, int nDeta, UINT uTimeOut)

{

// 保留原來的調色盤顏色表項

int nTotalColors = pPal->GetEntryCount();

PALETTEENTRY PaletteColors0[256];

pPal->GetPaletteEntries(0, nTotalColors, PaletteColors0);

// 設定時間碼

pWnd->SetTimer(0x100, uTimeOut, NULL);

// 開始漸隱

pWnd->SetCapture();

BOOL bDone = FALSE;

MSG msg;

while (! bDone)

{

if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{

if (msg.message == WM_TIMER && msg.wParam == 0x100)

{

CClientDC dc(pWnd);

CPalette *pOldPal = dc.SelectPalette(pPal, FALSE);

dc.RealizePalette();

PALETTEENTRY PaletteColors[256];

pPal->GetPaletteEntries(0, nTotalColors, PaletteColors);

BOOL bRedZero=FALSE;

BOOL bGreenZero=FALSE;

BOOL bBlueZero=FALSE;

// 遞減顏色分量

for (int i=0; i
{

if (PaletteColors[i].peRed > nDeta)

{

PaletteColors[i].peRed -= nDeta;

bRedZero = FALSE;

}

else if (PaletteColors[i].peRed > 1)

{

PaletteColors[i].peRed--;

bRedZero = FALSE;

}

else

bRedZero = TRUE;

if (PaletteColors[i].peGreen > nDeta)

{

PaletteColors[i].peGreen -= nDeta;

bGreenZero = FALSE;

}

else if (PaletteColors[i].peGreen > 1)

{

PaletteColors[i].peGreen--;

bGreenZero = FALSE;

}

else

bGreenZero = TRUE;

if (PaletteColors[i].peBlue > nDeta)

{

PaletteColors[i].peBlue -= nDeta;

bBlueZero = FALSE;

}

else if (PaletteColors[i].peBlue > 1)

{

PaletteColors[i].peBlue--;

bBlueZero = FALSE;

}

else

bBlueZero = TRUE;

}

// 如所有顏色分量都為0,則結束漸隱

bDone = bRedZero && bGreenZero && bBlueZero;

// 使系統改變調色盤

pPal->AnimatePalette(0, nTotalColors, PaletteColors);

}

::TranslateMessage(&msg);

::DispatchMessage(&msg);

}

}

::ReleaseCapture();

pWnd->KillTimer(0x100);

// 恢復原始調色盤

pPal->SetPaletteEntries(0, nTotalColors, PaletteColors0);

pPal->AnimatePalette(0, nTotalColors, PaletteColors0);

}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-995709/,如需轉載,請註明出處,否則將追究法律責任。

相關文章