【MFC】截图编辑插件技术总结(2):现有截屏API分析

时间:2014-07-11 09:37:45   收藏:0   阅读:797

作为系列博文的第一篇,先写些简单的吧,也是对自己学习过的东西的总结。

BitBlt

首先,是最常用的贴图函数之一的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

接下来要介绍的是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上刷新了,这样就会只复制该窗口的内容而不会被其他窗口干扰。因为只是进行了刷新,所以就无法截取带滚动条的窗口的全部内容了,只能截取可视区域的内容。

那要怎么解决这个问题呢?参考一些流行截图软件的做法,就是边移动滚动条,边截图,然后再把图片都拼接起来。但是,这又要怎么确保图片对齐呢?这里就不再讨论了,再讨论就跑题了,解决方案会在另一篇博文中作详细介绍,有兴趣的可以期待一下~

IViewObject::Draw

最后这个比较复杂,它主要用于截取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);

 

好的,截图函数的总结就先到这里了,第一次写博文感觉挺累的,以前做惯了伸手党,现在总算有点东西可以分享了。

本人水平有限,文中难免出现错漏,欢迎各位留言指出,但请注意文明用语,总之轻喷吧!

【MFC】截图编辑插件技术总结(2):现有截屏API分析,布布扣,bubuko.com

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!