当前位置:C++技术网 > 精选软件 > 对窗口中的图片进行反色选择处理大提速以及对图片反色的极速处理

对窗口中的图片进行反色选择处理大提速以及对图片反色的极速处理

更新时间:2015-12-16 21:56:40浏览次数:1+次

    在《Win32对窗口中的图片进行反色选择处理》中,我们单击鼠标后,开始对整个窗口进行反色处理。这个效率非常低,也就让我们看到了发色的慢动作,看起来挺爽!
    然而我们需要实际使用的话,这样也太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;
}