问题
如何抓取屏幕保存到bitmap文件?
方法
GDI 方法
1、抓取。
HBITMAP CRectChartUI::GetBitmap(HDC hDC)
{
HDC hMemDC;
int x, y;
int nWidth, nHeight;
HBITMAP hBitmap, hOldBitmap;
hMemDC = CreateCompatibleDC(hDC);
nWidth = GetDeviceCaps(hDC, HORZRES);
nHeight = GetDeviceCaps(hDC, VERTRES);
hBitmap = CreateCompatibleBitmap(hDC, nWidth, nHeight);
hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY);
hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
return hBitmap;
}
2、保存bitmap文件函数
// 保存位图到文件
int CScreenshotsWnd::SaveBitmapToFile(HBITMAP hBitmap, LPCWSTR lpFileName)
{
WORD wBitCount; //位图中每个像素所占字节数
// 定义调色板大小,位图中像素字节大小,位图文件大小,写入文件字节数
DWORD dwPaletteSize = 0, dwBmBitsSize, dwDIBSize, dwWritten;
BITMAP Bitmap; //位图属性结构
BITMAPFILEHEADER bmfHdr; //位图文件头结构
BITMAPINFOHEADER bi; //位图信息头结构
HANDLE fh; //定义文件,分配内存句柄,调色板句柄
LPSTR lpbk, lpmem;
wBitCount = 32;
//设置位图信息头结构
GetObject(hBitmap, 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.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmBitsSize = ((Bitmap.bmWidth*wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;
//创建位图文件
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) + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
//写入位图文件头
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
//写入位图信息头
WriteFile(fh, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwWritten, NULL);
//获取位图阵列
lpmem = new char[dwBmBitsSize];
lpbk = (LPSTR) new char[dwBmBitsSize];
GetBitmapBits(hBitmap, dwBmBitsSize, lpmem);//正向的内存图象数据
//转化为倒向数据(仅在bmHeight为正时需要)
for (int i = 0; i < Bitmap.bmHeight; i++)
{
memcpy(lpbk + Bitmap.bmWidth*i * 4, lpmem + Bitmap.bmWidth*(Bitmap.bmHeight - i - 1) * 4, Bitmap.bmWidth * 4);
}
//写位图数据
WriteFile(fh, lpbk, dwBmBitsSize, &dwWritten, NULL);
//清除
delete[]lpbk;
delete[]lpmem;
CloseHandle(fh);
return TRUE;
}
3、调用方式
SaveBitmapToFile(GetBitmap(hDC), _T("d:\\debug\\1.bmp"));
GDI+方法
1、抓屏幕保存至文件。
BOOL CRectChartUI::SaveHDCToFile(HDC hDC, Gdiplus::Rect rc, LPCWSTR lpFileName)
{
BOOL bRet = FALSE;
//将目标区域贴图到内存BITMAP
HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap = CreateCompatibleBitmap(hDC, rc.Width, rc.Height);
SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, rc.Width, rc.Height, hDC, rc.X, rc.Y, SRCCOPY);
//保存成文件
{
//L"image/bmp" L"image/jpeg" L"image/gif" L"image/tiff" L"image/png"
CLSID pngClsid;
GetEncoderClsid(L"image/bmp", &pngClsid);//此处以BMP为例,其它格式选择对应的类型,如JPG用L"image/jpeg"
Gdiplus::Bitmap *pbmSrc = Gdiplus::Bitmap::FromHBITMAP(hBitmap, NULL);
if (pbmSrc->Save(lpFileName, &pngClsid) == Gdiplus::Status::Ok)
{
bRet = TRUE;
}
delete pbmSrc;
}
//清理工作
SelectObject(hMemDC, (HBITMAP)NULL);
DeleteDC(hMemDC);
DeleteObject(hBitmap);
return bRet;
}
2、检索编码器的类标识符
BOOL CRectChartUI::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; //number of image encoders
UINT size = 0; //size of the image encoder array in bytes
int nRet;
UINT i;
ImageCodecInfo* pImageCodecInfo = NULL;
nRet = GetImageEncodersSize(&num, &size);
if (nRet != Gdiplus::Status::Ok)
{
return FALSE;
}
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if (pImageCodecInfo == NULL)
{
return FALSE;
}
GetImageEncoders(num, size, pImageCodecInfo);
for (i = 0; i < num; i++)
{
if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0)
{
*pClsid = pImageCodecInfo[i].Clsid;
free(pImageCodecInfo);
return TRUE;
}
}
free(pImageCodecInfo);
return FALSE;
}
3、调用方式。
SaveHDCToFile(hDC, rc, _T("d:\\debug\\test.bmp"));
总结
1、GDI+保存文件种类可以选择bmp、jpeg等多种,GDI只能是bmp。
2、流程基本一致,但GDI保存需要自己实现。
参考:【GDI+】GetEncoderClsid()函数,检索编码器的类标识符_sunriver2000的博客-CSDN博客