在QQ聊天窗口中,我们发送了图片后,然后选择图片后,图片就出现下面这样的效果:
下面是QQ聊天文字选择后的效果,原始的颜色是黑色,选择后为白色字:
下面是窗口原始图的效果:
窗口中反色处理后的效果:
其实我们最常见的是文字选择后的反色,各种可以打字的地方,选择文字后都反色处理了。只不过,系统默认的反色并不是绝对的反色,而是将选择文字的设置了一个较深的颜色罢了。而对于文字字体上,则由黑色变成了白色。
那么我们首先来看看什么是反色。不管是文字还是图像,窗口中显示的所有东西都是有像素组成的,而像素又会由三种基色(光的三基色:红绿蓝)合成,在设置颜色是使用的是RGB(红,绿,蓝),其实就是三基色合成一个颜色。对于颜色的基础背景知识,请在C++技术网即本网站搜索“色彩基础知识全面了解”搜到的是作者codeGod原创写作的文章,可以让你对色彩有一个比较深入的了解。
颜色的三个分量红绿蓝的取值都是从0-255这个范围。每一个像素点都由三个基色组成,从而显示为一个彩色。我们这里讨论的是真彩色,真彩色就是用24位即三个字节表示一个像素的颜色信息。
那么绝对的反色,就是将三个颜色分量的值在0-255范围内取反,如果当前像素的颜色为RGB(100,200,41),那么绝对反色之后,就是RGB(255-100,255-200,255-41)。如果刚好像素颜色是黑色,即RGB(0,0,0),绝对反色之后,就是RGB(255,255,255)即白色咯。
要进行反色处理,就要取得每一给像素的颜色信息,就是GetPixel函数获取的,然后使用SetPixel函数来设置颜色。主要的问题就是对要反色的区域进行像素的遍历。客户区就是一个像素矩阵,就是一个二维的像素数组,用行列即可遍历。
为了实现对图片的反色操作,我加在了一个美女图片,Win32中在窗口上显示图片的实现,已经在文章《Win32实现在窗口贴图,Win32设置窗口背景》详细分析了。
所以就接着介绍这部分的技术点。我在鼠标左键单击时开始循环遍历对像素反色。代码如下:
case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
for (int i=0;i<pt.x;i++)
{
for (int j=0;j<pt.y;j++)
{
COLORREF clr = GetPixel(hdc,i,j);
int red = GetRValue(clr);
int green = GetGValue(clr);
int blue = GetBValue(clr);
SetPixel(hdc,i,j,RGB(255-red,255-green,255-blue));
}
}
ReleaseDC(hwnd,hdc);
return 0;
至于GetRValue这三个宏的使用介绍以及COLORREF颜色类型的介绍,请参考《COLOR和COLORREF之间的理解与相互转换》。对于函数SiePixel的介绍,请参考《使用SetPixel在客户区自由绘画的功能实现》。
我们在鼠标单击时开始反色。因为对客户区所有的像素点进行遍历,你应该会猜测到一个问题,就是效率问题。是的,反色处理的效率极低,非常的慢,而在QQ中选择一个图片,瞬间就反色了。然而这个却带来了一个有趣的效果,即反色过程会慢慢的反色,可以看到动画效果,哈哈哈。也是很不错的感觉哦,可以让你慢慢欣赏反色的过程,很有意思哦,只是不能操作而已。同时,每次单击窗口都会反色。单击一次,得到不正常的图片,再单击一次,恢复正常,然后这样可以不停的反色。
那么对于反色效率问题,我将在后续的文章来分析,提高效率。
以下是本程序的完整代码:
#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;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
hBitmap = LoadBitmap(g_hInstance,MAKEINTRESOURCE(IDB_BITMAP1));
hMem = CreateCompatibleDC(hdc);
SelectObject(hMem,hBitmap);
TextOut(hMem,0,100,Info,lstrlen(Info));
BitBlt(hdc,0,0,pt.x,pt.y,hMem,0,0,SRCCOPY);
EndPaint(hwnd,&ps);
return 0;
case WM_LBUTTONDOWN:
hdc = GetDC(hwnd);
for (int i=0;i<pt.x;i++)
{
for (int j=0;j<pt.y;j++)
{
COLORREF clr = GetPixel(hdc,i,j);
int red = GetRValue(clr);
int green = GetGValue(clr);
int blue = GetBValue(clr);
SetPixel(hdc,i,j,RGB(255-red,255-green,255-blue));
}
}
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;
}