作为系列博文的第一篇,先写些简单的吧,也是对自己学习过的东西的总结。
首先,是最常用的贴图函数之一的BitBlt,作用是从源DC中拷贝指定大小的图片到目标DC中,至于DC是什么,这里就不再赘述了,请自行百度。下面给出该函数的参数列表:
BOOL BitBlt( HDC hdcDest,// 目标DC的Handle int nXDest, // 目标位置的左上角X坐标 int nYDest, // 目标位置的左上角Y坐标 int nWidth, // 需要拷贝的图片的宽 int nHeight,// 需要拷贝的图片的高 HDC hdcSrc, // 源DC的Handle int nXSrc, // 要拷贝图片的左上角X坐标 int nYSrc, // 要拷贝图片的左上角Y坐标 DWORD dwRop // 操作标志 );
需要注意的地方是,这里的坐标都是指DC中的坐标,可以认为DC是一个虚拟的显示设备,该设备以显示区域的左上角作为原点,X轴向右递增,Y轴向下递增,以此建立坐标系。下面以截取全屏为例说明函数用法:
m_width=GetSystemMetrics(SM_CXSCREEN);//获取屏幕分辨率 m_height=GetSystemMetrics(SM_CYSCREEN); hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);//为屏幕创建设备描述表 hMemDC = CreateCompatibleDC(hScrDC);//创建兼容的内存设备描述表 // 创建一个与屏幕设备描述表兼容的位图 hBitmap = CreateCompatibleBitmap(hScrDC, m_width,m_height); // 把新位图选到内存设备描述表中 hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); // 把屏幕设备描述表拷贝到内存设备描述表中 BitBlt(hMemDC, 0, 0, m_width, m_height, hScrDC, 0, 0, SRCCOPY);
这样就可以把屏幕截取到内存DC中用于后续操作了。最后说说操作标志这个参数,上面的代码中使用的是SRCCOPY,意思是直接复制,它还有很多选择,详情可以查看MSDN,可能用到的有SRCAND、SRCPAINT等,复制时将原图片与目标图片进行逻辑与,异或,或运算。可以产生一些特别的效果。
StretchBlt
StretchBlt是BitBlt的变形,主要用于图片的缩放。下面给出该函数的参数列表:
BOOL StretchBlt( HDC hdcDest, // 目标DC的Handle int nXOriginDest,// 目标位置的左上角X坐标 int nYOriginDest,// 目标位置的左上角Y坐标 int nWidthDest, // 图片目标宽度 int nHeightDest, // 图片目标长度 HDC hdcSrc, // 源DC的Handle int nXOriginSrc, // 要拷贝图片的左上角X坐标 int nYOriginSrc, // 要拷贝图片的左上角Y坐标 int nWidthSrc, // 要拷贝图片的宽度 int nHeightSrc, // 要拷贝图片的高度 DWORD dwRop // 操作标志 );
从参数可以看出StretchBlt比BitBlt多了两个描述宽度和高度的参数,如果目标宽度高度与源宽度高度都相同则该函数的作用与BitBlt一样。通过改变目标宽度和高度,StretchBlt允许用户在拷贝的同时缩放图片。
接下来要介绍的是PrintWindow函数,该函数的作用是截取整个窗口的内容。有人可能会问,用BitBlt就可以实现截取整个窗口的内容啦,为什么要有这个函数呢?其实,前面介绍的BitBlt函数有一个问题无法解决,那就是窗口遮挡问题,当想要截取的窗口被其他窗口遮挡住时,用BitBlt就无法截取完整的窗口内容了。这个时候就应该使用PrintWindow来截取完整窗口内容。下面给出函数的参数列表:
BOOL PrintWindow( HWND hwnd, // 要拷贝的窗口句柄 HDC hdcBlt, //图片保存的目标DC UINT nFlags // 操作标志 );
下面通过截取全屏来演示该函数的使用方法:
HWND hwnd=::GetDesktopWindow(); CRect* rect; ::GetWindowRect(hwnd,rect); int iWidth=rect->Width(); int iHeight=rect->Height(); HDC hScrDC = CreateDC(_T("DISPLAY"), NULL, NULL, NULL); HDC BufferDC; BufferDC=::CreateCompatibleDC(hScrDC); HBITMAP BufferBmp; BufferBmp=::CreateCompatibleBitmap(hScrDC,iWidth,iHeight); ::SelectObject(BufferDC,BufferBmp); ::PrintWindow(hwnd,BufferDC,NULL);
操作标志只有一个选项,就是PW_CLIENTONLY,意思是只截取窗口的用户区域部分,否则会全部截取。通过与前面函数的对比就会发现,PrintWindow并没有截取其他窗口的内容。下面说说本人遇到过的一个问题,PrintWindow能否截取带滚动条的窗口的完整内容?答案是不可以,为什么呢?不是说可以截取整个窗口的内容么?这涉及PrintWindow函数的具体实现,对于这个问题本人不想再深挖下去了,有兴趣的同学可以研究下,得出结论后麻烦告知一声啊!这里只提出我的一个猜想,根据MSDN上的资料,PrintWindow函数与WM_PAINT消息相似,众所周知,可以通过SendMessage函数向窗口发送WM_PAINT消息使其刷新窗口。那么,我猜PrintWindow函数是让窗口在指定的DC上刷新了,这样就会只复制该窗口的内容而不会被其他窗口干扰。因为只是进行了刷新,所以就无法截取带滚动条的窗口的全部内容了,只能截取可视区域的内容。
那要怎么解决这个问题呢?参考一些流行截图软件的做法,就是边移动滚动条,边截图,然后再把图片都拼接起来。但是,这又要怎么确保图片对齐呢?这里就不再讨论了,再讨论就跑题了,解决方案会在另一篇博文中作详细介绍,有兴趣的可以期待一下~
最后这个比较复杂,它主要用于截取IE浏览器的内容,但它不仅仅用于网页,微软的很多控件都实现了该方法,所以它也被用来截取控件内容。这里只对其作简要介绍,后面会写一篇关于网页截图的博文,敬请期待~下面给出函数参数列表:
HRESULT Draw( DWORD dwAspect, LONG lindex, void* pvAspect, DVTARGETDEVICE* ptd, HDC hicTargetDev, HDC hdcDraw,//保存图片的DC const LPRECTL lprcBounds, const LPRECTL lprcWBounds, BOOL (*) (DWORD)pfnContinue, DWORD dwContinue );
函数的大致用法:
pViewObject->Draw(DVASPECT_CONTENT,1,NULL,NULL,NULL,hIEMenDC2,&rectl,NULL,NULL,NULL);
好的,截图函数的总结就先到这里了,第一次写博文感觉挺累的,以前做惯了伸手党,现在总算有点东西可以分享了。
本人水平有限,文中难免出现错漏,欢迎各位留言指出,但请注意文明用语,总之轻喷吧!