然而我们需要实际使用的话,这样也太Low了。所以要想办法提高反色处理效率。我们的这次目标就是不对整个客户区发色了,只对图片大小反色。我们完全可以将范围缩小在图片大小的范围内的客户区反色,然而这个并没有卵用。因为这样还是很慢,没有多大的性能提升。所以这个方法放弃。
那么我们就瞄准了图片本身,如果贴图前就让图片反色好,然后一次性贴图,是不是会极大提高效率呢?答案是的。那么这样其实就是在处理图片数据了。而操作就是在内存中进行。那个内存DC已经载入了图片,在内存DC中设置像素颜色,就是将颜色设置在图片数据上了。内存DC中的图片将相当于画布了,我们的画图操作就是在这个图片上操作咯。实际上图片处理就是这么干的,操作完后保存图片数据,图片就被修改了。
好了,我们贴图的函数不变,将鼠标单击的反色处理移入WM_PAINT消息处理中处理。然而我们需要知道图片的大小,这样才好遍历对图片数据做反色处理哦。在Win32中如何获取位图的宽度和高度,请参考文章《Win32获取位图的信息之获取位图的宽度和高度》。
我们在将位图选进内存DC之后,然后开始用内存DC进行颜色的取反的反色操作。这样就会将反色信息直接写入内存中的图片数据中。使用是双层循环遍历,代码如下:
for (int i=0;i<bm.bmWidth;i++)
{
for (int j=0;j<bm.bmHeight;j++)
{
COLORREF clr = GetPixel(hMem,i,j);
int red = GetRValue(clr);
int green = GetGValue(clr);
int blue = GetBValue(clr);
SetPixel(hMem,i,j,RGB(255-red,255-green,255-blue));
}
}
这个代码和在单击鼠标时的没有两样,就是客户区的DC换成了内存DC而已。然后在执行代码看看效果。效果图如下:实际上看到的效果还是那个反色的效果,然而你不会看到慢慢的反色的动画效果了。因为它是一次性贴图到窗口的。窗口显示时会有一秒钟左右的黑色画面,因为窗口客户区背景是黑色的。改变窗口的大小时也是每次都会有黑色的闪屏。也就是说,实际上还是没有瞬间处理完毕。不过从数分钟到一秒的提速,有很大的改进。
然而,这个效果实际上还是在一些情况下让人无法接受。那么我们再进一步提速。这次的原理就不是自己来遍历设置了。其实你对这个循环的优化,也提高不了多少了。
那么下一个目标就是看到了视频适配器,只有在这个级别的处理,那才是最快的。那么要下手的函数就是贴图函数BitBlt了。
我们可以看到最后一个参数我们一直设置的是SRCCOPY。实际上就是将来源的图片的像素一对一的拷贝到窗口显示。而这个函数的实现是视频适配器级别的。他会对显示进行优化。最后一个参数的可选项有一个NOTSRCCOPY,这个表示对原始像素的值取反,其实就是我们说的绝对取反。
这个操作就是将像素的值按位取反,0变1,1变0。然而,你可以发现,这个取反会让200变为55,让150变成105等等,也就达到了我们所要的颜色的绝对取反了。而且,这个取反效率是非常高的,视频适配器级别,自然有优化的。
所以我们可以注释掉在内存中对图片像素取反的代码,直接将贴图代码改为:
BitBlt(hdc,0,0,pt.x,pt.y,hMem,0,0,NOTSRCCOPY);
然后执行后你会发现,反色的图片没有一点闪烁,瞬间完成的,眼睛都无法察觉。我们将这个反色做到这个地方,效率已经是无可挑剔的了。如此也发现,视频适配器(显卡)级别的处理属于底层硬件的处理级别,自然是最快的了。并且贴图函数就提供了这个选项哦。我想通过这一些过程的讲解,你对贴图函数的反色处理会有一个极大的深入和深刻的印象了。
下面给出完整的实现代码:
#include "windows.h"
#include "resource.h"
#include <tchar.h>
// - 项目是Unicode字符集
HINSTANCE g_hInstance=NULL;
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc,hMem;
PAINTSTRUCT ps;
TCHAR Info[100]=_T("美女哦 - 【C++技术网http://www.cjjjs.com】");
HBITMAP hBitmap;
static POINT pt;
BITMAP bm;//-位图信息结构体
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
hBitmap = LoadBitmap(g_hInstance,MAKEINTRESOURCE(IDB_BITMAP1));
GetObject(hBitmap, sizeof(bm), &bm);
hMem = CreateCompatibleDC(hdc);
SelectObject(hMem,hBitmap);
TextOut(hMem,0,100,Info,lstrlen(Info));
// - 在内存中对位图反色处理,效率还是不够高
//for (int i=0;i<bm.bmWidth;i++)
//{
// for (int j=0;j<bm.bmHeight;j++)
// {
// COLORREF clr = GetPixel(hMem,i,j);
// int red = GetRValue(clr);
// int green = GetGValue(clr);
// int blue = GetBValue(clr);
// SetPixel(hMem,i,j,RGB(255-red,255-green,255-blue));
// }
//}
BitBlt(hdc,0,0,pt.x,pt.y,hMem,0,0,NOTSRCCOPY);
EndPaint(hwnd,&ps);
return 0;
case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
ReleaseDC(hwnd,hdc);
return 0;
case WM_SIZE:
pt.x = LOWORD(lParam);//存储客户区宽度
pt.y = HIWORD(lParam);//存储客户区高度
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
TCHAR ClassName[] = _T("MyClass");
TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
WNDCLASS wndClass;
wndClass.cbClsExtra=0;
wndClass.cbWndExtra=0;
wndClass.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndClass.hInstance = hInstance;
wndClass.lpfnWndProc = WinProc;
wndClass.lpszClassName = ClassName;
wndClass.lpszMenuName=NULL;
wndClass.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClass(&wndClass))
{
return 0;
}
g_hInstance = hInstance;
HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,440,440,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}