|
摘 要 图
象 的 渐 显/ 渐 隐 被 广 泛 运 用 与 图 象 处 理 和 多 媒 提 娱 乐 软 件。 本 文 基 于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; iSetPaletteEntries(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 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 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);
}
|