分享
 
 
 

用Visual C++实现图象渐显和渐隐

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

用Visual C++实现图象渐显和渐隐

周长发

摘 要 图象的渐显/渐隐被广泛运用与图象处理和多媒提娱乐软件。本文基于Windows的调色板动画和时间码技术设计了通用的图象渐显和渐隐算法,并实现了其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::SelectPalette和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<nTotalColors; ++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<nTotalColors; ++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<nTotalColors; ++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);

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有