2012-03-19 20:42:56|?次阅读|上传:wustguangh【已有?条评论】发表评论
关键词:C/C++, MFC, 操作系统, 图形/图像|来源:唯设编程网
在实际项目中,经常会用到截屏的功能,于是自己使用VC编写了一个实现截屏功能的MFC DLL,以备随时可以使用。该项目实现了屏幕指定区域截图、全屏用户交互式截图、保存截图结果到位图(BMP)文件等功能,下面分步骤详细介绍具体的设计方案和实现代码。
首先显示程序的运行效果:
1. 创建一个名称为ScreenSnap的MFC DLL项目到解决方案中,DLL类型选择MFC扩展DLL;
2. 在项目ScreenSnap中创建类ScreenShutter,用于提供用户调用屏幕截图操作的接口。该类主要实现屏幕截图的基本功能:保存屏幕截图到位图(BMP)文件、返回指定范围的截图、返回截图的完整区域位图。
示例:
class AFX_EXT_CLASS CScreenShutter { private: CDC ScrDC; //显示器DC public: CBitmap* m_pBitmap;//存储背景图片(成员变量) public: CScreenShutter(void); ~CScreenShutter(void); // 保存m_pBackBitmap中储存的位图数据到磁盘文件中 BOOL SaveBitmapToFile(LPCWSTR lpFileName); // 截图屏幕指定区域 // 结果保存在成员变量m_pBackBitmap中 CScreenShutter* getScreenBitmap(POINT pt1,POINT pt2); // 截图屏幕完整区域 // 结果保存在成员变量m_pBackBitmap中 CScreenShutter* getScreenBitmap(); };
备注:在CScreenShutter前面增加AFX_EXT_CLASS使该类为DLL的导出类。
示例:
CScreenShutter::CScreenShutter(void) :m_pBitmap(NULL) { } CScreenShutter::~CScreenShutter(void) { //清除位图资源 if (m_pBitmap != NULL) { delete m_pBitmap; m_pBitmap = NULL; } }
示例:
// 把Cbitmap对象保存到文件中 // lpFileName 为位图文件名 BOOL CScreenShutter::SaveBitmapToFile(LPCWSTR lpFileName) { //设备描述表 HDC hDC; //当前分辨率下每象素所占字节数 int iBits; //位图中每象素所占字节数 WORD wBitCount; //定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数 DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0; //位图属性结构 BITMAP Bitmap; //位图文件头结构 BITMAPFILEHEADER bmfHdr; //位图信息头结构 BITMAPINFOHEADER bi; //指向位图信息头结构 LPBITMAPINFOHEADER lpbi; //定义文件,分配内存句柄,调色板句柄 HANDLE fh, hDib, hPal,hOldPal=NULL; //计算位图文件每个像素所占字节数 hDC = CreateDC(_T("DISPLAY"), NULL, NULL, NULL); iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES); DeleteDC(hDC); if (iBits <= 1) wBitCount = 1; else if (iBits <= 4) wBitCount = 4; else if (iBits <= 8) wBitCount = 8; else wBitCount = 24; GetObject(*m_pBitmap, sizeof(Bitmap), (LPSTR)&Bitmap); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = Bitmap.bmWidth; bi.biHeight = Bitmap.bmHeight; bi.biPlanes = 1; bi.biBitCount = wBitCount; bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrImportant = 0; bi.biClrUsed = 0; dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight; //为位图内容分配内存 hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); if(hDib==NULL) return false; lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib); *lpbi = bi; // 处理调色板 hPal = GetStockObject(DEFAULT_PALETTE); if (hPal) { hDC = ::GetDC(NULL); hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE); RealizePalette(hDC); } // 获取该调色板下新的像素值 GetDIBits(hDC, *m_pBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) +dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS); //恢复调色板 if (hOldPal) { ::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE); RealizePalette(hDC); ::ReleaseDC(NULL, hDC); } //创建位图文件 fh = CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (fh == INVALID_HANDLE_VALUE) return FALSE; // 设置位图文件头 bmfHdr.bfType = 0x4D42; // "BM" dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; bmfHdr.bfSize = dwDIBSize; bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; // 写入位图文件头 WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); // 写入位图文件其余内容 WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL); //清除 GlobalUnlock(hDib); GlobalFree(hDib); CloseHandle(fh); return TRUE; }
该函数将CBitmap类型的成员指针m_pBitmap所指的位图数据保存到磁盘文件,实现了CBitmap保存到磁盘文件的通用方法,实现过程比较麻烦,读者可以在其它项目直接重用该段代码。
// 截图屏幕指定区域 // 结果保存在成员变量m_pBackBitmap中 CScreenShutter* CScreenShutter::getScreenBitmap(POINT pt1,POINT pt2){ //NEW资源(调用一次重新拷贝一次) if (m_pBitmap != NULL) { delete m_pBitmap; m_pBitmap = NULL; } m_pBitmap = new CBitmap(); CDC ScrDC,MemDC; ScrDC.CreateDC(_T("DISPLAY"), NULL, NULL, NULL); MemDC.CreateCompatibleDC(&ScrDC); //创建位图 m_pBitmap->CreateCompatibleBitmap(&ScrDC,abs(pt1.x-pt2.x),abs(pt1.y-pt2.y)); MemDC.SelectObject(m_pBitmap); //拷贝屏幕的区域到创建的位图中 int minX=pt1.x<pt2.x?pt1.x:pt2.x; int minY=pt1.y<pt2.y?pt1.y:pt2.y; MemDC.BitBlt(0, 0, abs(pt1.x-pt2.x), abs(pt1.y-pt2.y),&ScrDC,minX, minY,SRCCOPY); ScrDC.DeleteDC(); MemDC.DeleteDC(); return this; }
该函数使用设备描述表CDC实现屏幕截图,并将截图结果保存在pBitmap所指的位图存储空间中。调用CreateDC创建一个特定的设备描述表,调用CBitmap的成员函数CreateCompatibleBitmap初始化与对应设备描述表兼容的位图到m_pBitmap所指的位图空间。最后调用BitBlt实现将ScrDC设备描述表指定区域的位图拷贝到MemDC设备描述表。
// 交互式截图 // 结果保存在成员变量m_pBackBitmap中 CScreenShutter* CScreenShutter::getScreenBitmap(){ //显示位图 AFX_MANAGE_STATE(AfxGetStaticModuleState()); CScreenSnapDlg dlg(m_pBitmap); dlg.DoModal(); return this; }
特别注意:由于在MFC扩展DLL中使用了自定义的对话框类,在调用前请添加语句
AFX_MANAGE_STATE(AfxGetStaticModuleState());
该类调用屏幕截图对话框CScreenSnapDlg实现全屏用户交互式截图,限于篇幅,CScreenSnapDlg类我们将在下一篇文章中进行介绍。