怎样得到鼠标光标图相关信息(DirectX 截图取得光标 的方法)
2012-12-15 01:00
316 查看
缘由: 由于DirectX 作截图渲染的时候.. 截取整个桌面的图时,它没有得到光标... 对于做桌面的融合等时,在扩展桌面的操作因为看不到
鼠标光标的原因.对操作带来一定的不便.. 所以要想办法把光标也一起截图渲染的时候搞过去...
解决方案: 得到光标的图的相关信息. 在用DirectX 得到截取桌面图后.. 直接改写对应的像素数据.. (一般光标是 32*32,要改写的数据也就是这么多.效率方面一般不受影响的...)
本文示例程序: 可到我的资源下得到: GetCursorIco.rar...
具体步骤:在MFC 中利用对话框,加一个按钮,对应的函数如下即可>>
不足: 本文其实没有达到能截取到动态鼠标光标的目的,虽然这种应用场合比较少.. 我找了很多专业的截图工具,都是没有截取到动态光标,., 也就是比较一个"忙" 的光标,每次截取的时候,都仅截取到,那光标的第一帧图...
这种应用场合:如果要做截图渲染,每秒几十帧,上百帧的.. 那里截得的光标就不会动态了.. 这种没有解决.,如果有谁有更好的方法.可以告知一下..
wen438671344@qq.com
鼠标光标的原因.对操作带来一定的不便.. 所以要想办法把光标也一起截图渲染的时候搞过去...
解决方案: 得到光标的图的相关信息. 在用DirectX 得到截取桌面图后.. 直接改写对应的像素数据.. (一般光标是 32*32,要改写的数据也就是这么多.效率方面一般不受影响的...)
本文示例程序: 可到我的资源下得到: GetCursorIco.rar...
具体步骤:在MFC 中利用对话框,加一个按钮,对应的函数如下即可>>
不足: 本文其实没有达到能截取到动态鼠标光标的目的,虽然这种应用场合比较少.. 我找了很多专业的截图工具,都是没有截取到动态光标,., 也就是比较一个"忙" 的光标,每次截取的时候,都仅截取到,那光标的第一帧图...
这种应用场合:如果要做截图渲染,每秒几十帧,上百帧的.. 那里截得的光标就不会动态了.. 这种没有解决.,如果有谁有更好的方法.可以告知一下..
wen438671344@qq.com
void CGetCursorIconDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 // for (int i = 0; i < 200; i++) { // Sleep(2000); DrawCursor(100, 100); } } // 功能:画光标 // posX: 光标要画到的x 坐标,posY :光标要画到的y 坐标. // 附注: 整个函数内容啰嗦.. 为了达到把相应的图输出来观察.加入了不少内容...都是学习的原因.. // 正式场合使用时,可写得精简.. void CGetCursorIconDlg::DrawCursor(const int posX, const int posY) { // 参考 http://bbs.csdn.net/topics/300196964 //Sleep(2000);// 停2 秒,方便点击了按钮后,移到别的地方能截到别处的光标.(不延时,一点就取到当时的光标了,不利于观察) CURSORINFO ci; ci.cbSize=sizeof CURSORINFO; if( !(::GetCursorInfo(&ci) )) return; // 判断光标是否为显示状态,若不是,则返回 if (ci.flags != CURSOR_SHOWING) return; #if 0 // 得到光标图标信息 ICONINFO iconif; ZeroMemory(&iconif, sizeof(iconif)); ::GetIconInfo(ci.hCursor,&iconif); // 这样直接得到容易出错,见下面分析 #else HICON hCursorCopy; // 注意啊.如果不用这一句,把原来的的位图信息拷贝出来的话. 如果下面的信息操作的时间长一点的话,但是 // 光标在移动的时候已经有变化了.这里光标指向的句柄指向都已经改变了.所以再用 GetBitmapBits 得到的数据时.. // 就出错了.. // 所以,要用到光标的位图信息时,最好是先拷贝一次数据出来... // // 2012.12.18 by benben hCursorCopy = ::CopyIcon(ci.hCursor); // 得到光标图标信息 ICONINFO iconif; ZeroMemory(&iconif, sizeof(iconif)); ::GetIconInfo(hCursorCopy, &iconif); #endif ////////////////////////////////////////////////////////////////////////// // 把光标图标的 颜色图 保存下来观察下(注意,这里要判断一下句柄是否为空,因为有些黑白图标则没有这个颜色图,比如 I-Beam 光标) CImage image; if (NULL != iconif.hbmColor) { // 注意啊. 对于一些光标为黑白两种颜色的,根本就不需要 颜色位图.所以这时,hbmColor 为空的情况也是有的..所以这里要判断 // 句柄是否为空. image.Attach(iconif.hbmColor); image.Save(_T("..\\cursor\\color.bmp")); image.Detach(); } // 保存 掩码图 image.Attach(iconif.hbmMask); image.Save(_T("..\\cursor\\mask.bmp")); image.Detach(); // ////////////////////////////////////////////////////////////////////////// // 从磁盘上加载一幅图.看测试的效果,把测试的效果图输出到 文件夹 cursor 目录下 HBITMAP hBitmap = LoadBitmap(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDB_BITMAP1)); BITMAP bitmap_Src ; GetObject(hBitmap, sizeof(BITMAP), &bitmap_Src); CImage imgSource; imgSource.Attach(hBitmap); BITMAP bitmap_mask; // 得到光标 掩码图相关的信息, 注意 bitmap_mask. bmBits 的结果为NULL, // 可以用 GetBitmapBits 得到数据像素位的信息 GetObject(iconif.hbmMask, sizeof(BITMAP), &bitmap_mask); BITMAP bitmap_color; GetObject(iconif.hbmColor, sizeof(BITMAP), &bitmap_color); HDC hDC = NULL ; HBITMAP hOldBitmap = NULL ; if (NULL != iconif.hbmColor) { #ifdef NEW_VERSION hDC = ::CreateCompatibleDC( NULL ); if(!hDC) return; hOldBitmap = HBITMAP( ::SelectObject( hDC, iconif.hbmColor ) ); #else int cBytes = bitmap_color.bmWidthBytes * (bitmap_color.bmHeight); char *pBitColor = new char[cBytes]; GetBitmapBits(iconif.hbmColor, cBytes, pBitColor); #endif } int maskBytes = bitmap_mask.bmWidthBytes * (bitmap_mask.bmHeight); char *pBitMask = new char[maskBytes]; GetBitmapBits(iconif.hbmMask, maskBytes, pBitMask); // 这里应该判断一下能否内存申请成功的.. 这里只是 demo .我没有这样做了.. 注意一下.这在实际应用中需要改成类似于 // 以下的.. // 其实我觉得这里因为经常调用.. 用类成员变量(或全局变量)<一个保存内存块的指针,另一个保存大小>来保存申请的内存空间.. // 没有必要每次进入时申请,离开时释放... 应该这样:申请一块内存后.不释放 .. 到下次用到时.. // 判断下次要用到的内存有没有大于当前已经申请的,如果是大于当前已经申请的,才释放当前,另申请一块内存..( benben) // e.g. //if ( (!m_pBufferMask) || (m_MaskBytes < BMask) ) // 指针为空 或 当前已经申请的内存小于现在即将要用到的内存的大小 //{ // if(m_pBufferMask) delete m_pBufferMask; // m_pBufferMask = new char[BMask]; // if(!m_pBufferMask) break; // 申请内存空间不成功. // m_MaskBytes = BMask; // 保存当前申请的内存空间的大小 //} // 解说:对于光标为黑白图的.得到的iconif.hbmMask 的图 就是 32*64(前半部分与 要贴光标的图作"与"运算. // 后半部分,则与图作 "异或" 运算.. if (NULL != iconif.hbmColor) { for (int row = 0; row < bitmap_color.bmHeight; ++row) { for (int col = 0; col < bitmap_color.bmWidth; ++col) { COLORREF color = imgSource.GetPixel(col+ posX, row+posY); DWORD red = GetRValue(color); DWORD green = GetGValue(color); DWORD blue = GetBValue(color); // 与光标掩码图 作 "与" 运算 DWORD ret = getBitValue(bitmap_mask.bmWidth, bitmap_mask.bmHeight, pBitMask, col, row); // 注意以下三句不要写成 color &= ret; red &= ret; green &= ret; blue &= ret; #ifdef NEW_VERSION // 这个是新的版本.. // 今天和同事讨论到这个彩色图像不一定就是每个像素是 32 来存储.. // 如果是 32位(也就是说用 24 位表示颜色的情况, 没有颜色映射表.所以像我这样做也就足够了..) // 如果这个光标的颜色图可能是其他种类的(比如用 16 位来表示一个像素的时候.要显示到屏幕上)必然会有 // 一个颜色映射表... 一个方案是可以自己考虑来通过 位图信息的相关数据来做.. 另一个方案即是我参考了 // MFC 源码的 CImage 类(找atlimage.h这个头文件) 的成员函数 CImage::GetPixel(int, int) 的做法.. // COLORREF clr = ::GetPixel( hDC, col, row); red |= GetRValue(clr); green |= GetGValue(clr); blue |= GetBValue(clr); #else // 原始版本 // 与光标颜色图 作 "或" 运算(注意以下的顺序) blue |= pBitColor[bitmap_color.bmWidthBytes * row + col * (bitmap_color.bmBitsPixel/8)]; green |= pBitColor[bitmap_color.bmWidthBytes * row + col * (bitmap_color.bmBitsPixel/8) + 1]; red |= pBitColor[bitmap_color.bmWidthBytes * row + col * (bitmap_color.bmBitsPixel/8) + 2]; #endif // 把原来像素设置回去 imgSource.SetPixel(col+posX, row+posY, RGB(red, green, blue)); } } } else { for (int row = 0; row < bitmap_mask.bmHeight/2; ++row) { for (int col = 0; col < bitmap_mask.bmWidth; ++col) { COLORREF color = imgSource.GetPixel(col+posX, row+posY); // 这里取得像素数据 DWORD red = GetRValue(color); DWORD green = GetGValue(color); DWORD blue = GetBValue(color); DWORD ret = getBitValue(bitmap_mask.bmWidth, bitmap_mask.bmHeight, pBitMask, col, row); color &= ret; ret = getBitValue(bitmap_mask.bmWidth, bitmap_mask.bmHeight,\ pBitMask, col, bitmap_mask.bmHeight /2 + row); // 取得后半部分图的对应像素位 color ^= ret; // 把原来像素设置回去 imgSource.SetPixel(col+posX, row+posY, color); } } } imgSource.Save(_T("..\\cursor\\result.bmp")); imgSource.Detach(); // 释放资源 if(pBitMask) delete pBitMask; #ifdef NEW_VERSION if(hDC) ::DeleteDC( hDC ); if(hOldBitmap) ::SelectObject( hDC, hOldBitmap ); #else if(pBitColor) delete pBitColor; #endif // 检测内存泄漏.. _CrtDumpMemoryLeaks(); ////////////////////////////////////////////////////////////////////////// // ...... // 这下面可能做DirectX 相关的渲染操作.. // ... } // 功能: 取得单色图对应像素位的信息 // 返回值; 如果对应该位为 1 ,则返回0xffffffff; 如果对应位为 0, 则返回 0 DWORD CGetCursorIconDlg::getBitValue(int width, int height, void* p, int x, int y) { char *pBit = (char*)p; int num = x/8; int bits = x % 8; if(1 == ((pBit[(width/8) * y + num] >> (7 - bits) ) & 1)) { return 0xffffffff; } else { return 0; // 注意如果是像DirectX 得,有 阿尔法 值的情况,这里可返回 0Xff000000; 这样就不至于影响到 阿尔法的值了... } }
相关文章推荐
- intra-mart中取得登陆用户相关信息的数据的方法
- 怎样用js得到当前页面的url信息方法(JS获取当前网址信息)
- MySQL中show命令方法得到表列及整个库的详细信息(精品珍藏)
- C#调用dos窗口获取相关信息的方法
- 用 javascript 获取当页面上鼠标(光标)位置 和 触发事件的对象 的方法
- C#获取程序文件相关信息的方法
- 亲身体会:一种需要取得子类详细信息的情况(五种方法)
- Java获取系统信息(cpu,内存,硬盘,进程等)的相关方法
- 如何用js得到当前页面的url信息方法(JS获取当前网址信息)
- 利用OleDb的GetOLEDBSchemaTable方法得到数据库架构信息
- 如何用js得到当前页面的url信息方法(JS获取当前网址信息)
- 扩展类库:使用微软的 Visual Studio International Pack 1.0 进行网站简体与繁体的互转和得到汉字、拼音、笔画等相关信息
- JAVA异常信息Exception e,e的相关方法
- 通过rowid得到数据块的相关信息
- 正确得到线程退出信息的方法详解-变量存储退出信息结构、使用动态存储的方式退出信息结构、使用全局变量方式推相互信息结构、使用main函数中的局部变量存储退出信息结构
- Java获取系统信息(cpu,内存,硬盘,进程等)的相关方法 .
- Java获取系统信息(cpu,内存,硬盘,进程等)的相关方法
- Java获取系统信息(cpu,内存,硬盘,进程等)的相关方法
- 取得当前鼠标的X,Y坐标,及相关属性的介绍
- MySQL中show命令方法得到表列及整个库的详细信息(精品珍藏)