win抓取屏幕弄成流数据&流数据展示

一. 概念

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);

你可能感兴趣的:(windows)