当前位置:C++技术网 > 精选软件 > 设置绘图方式SetROP2实现反色绘图:白画布画黑线,黑画布画白线

设置绘图方式SetROP2实现反色绘图:白画布画黑线,黑画布画白线

更新时间:2015-12-19 19:25:31浏览次数:1+次

    在《对窗口中的图片进行反色选择处理大提速以及对图片反色的极速处理》系列文章中,已经讲述过反色绘图的自定义实现,就是自己取像素颜色,然后反色。通常用于图片的反色,文字显示反色处理。
    今天讲的是可以绘图过程中实时反色。这个效果用前面自己取色反色绘图也是可以实现的,但是如果这么做的话,效率跟不上,就出现滑动快了断线情况。而如果用画线方式解决断线问题,那么每一个点的就不能得到反色的效果了。因为一条直线经过的点,我们不会都去处理一遍,不然效率就和用SetPixel实现划线差不多了,甚至更差。对于SetPixel实现划线的实现分析,你可以参考《使用SetPixel在客户区自由绘画的功能实现》。
    所以,实时绘图的发色效果还不断线,我们还是得用一个高效的方式,就是设置绘图方式,设置绘图方式的函数是SetROP2。因为这个实现是基于视频适配器级别的实现,所以效率也很高。设置了绘图方式之后,DC会自动保证反色,我们只管画连续的线即可。这就用上了原先我们用线条自由绘图的技术,而反色则只要设置绘图方式即可。

    我们可以看看效果先:

设置绘图方式后自由的反色绘图

设置绘图方式后自由的反色绘图
    我们在客户区中画图,默认使用黑色的画笔。默认的绘图方式就是将画笔的颜色覆盖客户区对应的像素的颜色。这个模式叫做拷贝像素方式。那么客户区的像素我们叫做目标,也可以叫做画板,也可以叫做画布。我们调用函数SetROP2,传入R2_NOT参数,就可以将画板的像素取反绘画。也就是说,此时忽略画笔的颜色,最终在客户区上显示的颜色,由客户区当前的像素颜色每一位取反得到,如果客户区的颜色全是白色,那么在上面画的都是黑色的,如果客户区既有白色,也有黑色,那么画笔经过白色画黑线,经过黑色画白线。如果客户区有彩色,那么画笔经过后画的颜色就是RGB(255-红色分量,255-绿色分量,255-蓝色分量),三个颜色分量就是客户区的,用255去减掉分量后,最后形成的颜色就是反色了。所以,画笔经过红色后画的颜色就是青色,经过绿色客户区后画的是品色,经过蓝色就画的是黄色等等。你可以试试效果哦。
    而这一切,都是建立在客户区已有的颜色,第一次画图画的黑色,留下来之后,第二次画,就将上一次画的黑色作为客户区的这个点的像素,然后取反得到白色。每一次绘画都沉淀下来,成为客户区的颜色的一部分了。所以,在同一个位置画两次就成了客户区原本的颜色,反反得正的道理。
    那么这个效果,我们只要简单的在绘画前设置绘图方式,然后就到达反色绘画的效果。至于你要画什么,则是你要做的事情。

    最后说一下,这个绘图方式并不影响文字的输出,经过测试,文字输出始终在最顶层,而且设置什么颜色就输出什么颜色,与绘图方式无关。不信你可以在客户区鼠标移动时输出一个文字就可以看到了。我在提供的源码里,就有输出文字的代码。

    下面是完整的代码:


#include "windows.h"
#include <Windowsx.h>//GET_X_LPARAM,GET_Y_LPARAM宏需要这个头文件
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    static bool bisPaint=false;
    TCHAR Info[100]=_T("■■■■■■■■■■■■■■");
    static POINT ptOld;
    switch (message)
    {
     case WM_PAINT:
         hdc = BeginPaint(hwnd,&ps);//会清除无效矩形
         SetROP2(hdc,R2_NOT);
         SetBkMode(hdc,TRANSPARENT);

         SetTextColor(hdc,RGB(255,0,0));
         TextOut(hdc,0,10,Info,lstrlen(Info));
         Rectangle(hdc,10,150,300,300);//默认白色画刷,所以是白色的实心矩形
         EndPaint(hwnd,&ps);
         return 0;
     case WM_LBUTTONDOWN:
         bisPaint=true;//开始作画
         ptOld.x = GET_X_LPARAM(lParam); 
         ptOld.y = GET_Y_LPARAM(lParam); 
         return 0;
     case WM_LBUTTONUP:
         bisPaint=false;//松开鼠标,结束绘画
         return 0;
     case WM_KEYDOWN:
         InvalidateRect(hwnd,NULL,TRUE);
         return 0;
     case WM_MOUSEMOVE:
         if(bisPaint)//如果按着鼠标时,表示在作画,因此可以开始绘制
         {
             hdc = GetDC(hwnd);
             SetROP2(hdc,R2_NOT);
             SetBkMode(hdc,TRANSPARENT);
             SetTextColor(hdc,RGB(255,0,0));
             //文本输出在最顶层
             TextOut(hdc,10,100,_T("输出的文本测试是否反色显示,设置颜色为红色,反色后为青色"),lstrlen(_T("输出的文本测试是否反色显示,设置颜色为红色,反色后为青色")));

             MoveToEx(hdc,ptOld.x,ptOld.y,NULL);
             SelectObject(hdc,CreatePen(PS_SOLID,1,RGB(255,0,0)));
             LineTo(hdc,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
             ptOld.x = GET_X_LPARAM(lParam); 
             ptOld.y = GET_Y_LPARAM(lParam);
             ReleaseDC(hwnd,hdc);
           }
         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;
    }

    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,440,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}