1.设备dc
DC实际上是GDI内部保存的数据结构。
DC与特定的显示设备(如显示器或打印机)相关。
对于显示器,DC总是与显示器上的特定视窗相关。
DC中的有些值是图形「属性」,这些属性定义了GDI绘图函数工作的细节。
例如,对於TextOut,DC的属性确定了文字的颜色、文字的背景色、x座标和y座标映射到视窗的显示区域的方式,以及显示文字时Windows使用的字体。
MSDN的解释:一个DC是一个结构,它定义了一系列图形对象的集合以及它们相关的属性,以及影响输出效果的一些图形模式。这些图形对象包括一个画线的笔,一个填充和painting的画刷,一个用来向屏幕拷贝的位图,一个定义了一系列颜色集合的调色板,一个用来剪裁等操作的区域,一个做painting和drawing操作的路径。
一个应用程序从不直接地访问(access)dc,常见的取得dc的方式有以下几种:
SDK's way:
[1]. BeginPaint
case WM_PAINT: HDC hdc = BeginPaint(hwnd, &ps);EndPaint(hwnd, &ps);
MSDN的解释: BeginPaint函数自动地设置dc的剪裁区域,这个剪裁区域,剪裁的是由InvalidateRect 或 InvalidateRgn函数触发的窗口无效区域,或者是系统给出的无效区域,当窗口被sizing,moving, creating, scrolling, or any other operation that affectsthe client area.
一个应用程序从不调用BeginPaint,除了在收到一个WM_PAINT消息的时候;每一BeginPaint调用之后,需要调用EndPaint函数。
[2].GetXXXDC
GetDC取得与窗口客户区相关的dc,GetWindowDC取得与整个窗口(包括客户区和非客户区)相关的dc。
2. 内存dc
是一个虚拟的内存设备上下文,我们对它进行绘图等操作,不会显示在屏幕或打印机上,而我们可以在它完成之后,拷贝到屏幕上或打印机上来输出,这样我们可以避免因为操作而给屏幕带来的闪烁,对于打印机而言,打印只能是从上往下打,而我们在MEMDC中,可以随意进行操作,这样可以输出直接在打印机上输出所达不到的效果.
在窗口上贴图一般总是要用到内存DC,将所有的绘制工作先绘制在内存DC上,然活一次性拷贝到屏幕DC上,就是这样了。
1. 获取屏幕流
HWND hDeskTopWnd = ::GetDesktopWindow();//获得屏幕的HWND.
HDC hScreenDC = ::GetDC(hDeskTopWnd); //获得屏幕的HDC.
HDC MemDC = ::CreateCompatibleDC(hScreenDC); //创建一个内存中的DC
RECT rect;
::GetWindowRect(hDeskTopWnd, &rect);
SIZE screensize;
screensize.cx = rect.right - rect.left;
screensize.cy = rect.bottom - rect.top;
HBITMAP hBitmap;
hBitmap = ::CreateCompatibleBitmap(hScreenDC, screensize.cx, screensize.cy); //创建一个内存中的位图
HGDIOBJ hOldBMP = ::SelectObject(MemDC, hBitmap); //把位图和DC绑定在一起
BitBlt(MemDC, 0, 0, screensize.cx, screensize.cy, hScreenDC, 0, 0, SRCCOPY); //把整个屏幕的内容复制到内存DC中
BITMAPINFO bitInfo = { 0 };
bitInfo.bmiHeader.biSize = sizeof(bitInfo.bmiHeader);
//第一次调用GetDIBits获得图片的大小
int result = -1;
result = ::GetDIBits(MemDC, hBitmap, 0, screensize.cy, nullptr, &bitInfo, DIB_RGB_COLORS);
bitInfo.bmiHeader.biCompression = BI_RGB;
bitInfo.bmiHeader.biPlanes = 1;
if (result)
{
char* tempBuffer = (char*)malloc(bitInfo.bmiHeader.biSizeImage);
memset(tempBuffer, 0, bitInfo.bmiHeader.biSizeImage);
//第二次调用GetDIBits取图片流数据
GetDIBits(MemDC, hBitmap, 0, screensize.cy, tempBuffer, &bitInfo, DIB_RGB_COLORS);
//...............
free(tempBuffer);
}
::SelectObject(MemDC, hOldBMP);
::DeleteObject(MemDC);
::ReleaseDC(hWnd, hScreenDC);
2. 显示流数据
//nWidth图片的宽度,nHeight图片的高度,pImgBuffer里面装的是数据流,此处只是给出个形式
LONG nWidth;
LONG nHeight;
std::vector pImgBuffer;
//此处如果来源的流数据是ARGB,需要转成BGRA
auto& buffer = pImgBuffer;
for (int index_i = 0; index_i < (INT)tempSize; index_i += 4) {
auto temp = buffer.data()+index_i;
std::swap(temp[0], temp[3]);
std::swap(temp[1], temp[2]);
}
HDC hdc;
hdc = GetDC(m_hd);
BITMAPINFO bitInfo = { 0 };
bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitInfo.bmiHeader.biHeight = -nHeight;
bitInfo.bmiHeader.biWidth = nWidth;
bitInfo.bmiHeader.biPlanes = 1;
bitInfo.bmiHeader.biBitCount = 32;
bitInfo.bmiHeader.biSizeImage = tempSize;
bitInfo.bmiHeader.biCompression = BI_RGB;
//当图像涉及到缩小的时候,一定要加下面这句,要不然图片会失真
SetStretchBltMode(hdc, STRETCH_HALFTONE);
StretchDIBits(
hdc,
0,
0,
nWidth,
nHeight, //目标rect范围
0,
0,
nWidth,
nHeight, //源rect范围
pImgBuffer.data(),
(BITMAPINFO*)&bitInfo,
DIB_RGB_COLORS,
SRCCOPY);