1. 程式人生 > >VC螢幕截圖,儲存為Bmp檔案

VC螢幕截圖,儲存為Bmp檔案

新建一個MFC基於對話方塊的應用程式,在介面上放一個Button,為其實現點選事件,程式碼如下:

void CScreenShotDlg::OnBtnScreenshot()
{
	RECT rect = {0, 0, 1900, 1000};
	HBITMAP hbmp = CopyScreenToBitmap(&rect);
	SaveBitmapToFile(hbmp, "a.bmp");
	MessageBox("Save bmp file Successful");
}

被呼叫的這兩個函式實現如下:
HBITMAP CopyScreenToBitmap(LPRECT lpRect)
{
	HDC hScrDC, hMemDC;				// 螢幕和記憶體裝置描述表
	HBITMAP hBitmap, hOldBitmap;	// 點陣圖控制代碼
	int nX, nY, nX2, nY2;			// 選定區域座標
	int nWidth, nHeight;			// 點陣圖寬度和高度
	int xScrn, yScrn;				// 螢幕解析度

	if (IsRectEmpty(lpRect))
		return NULL;

	hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);		// 為螢幕建立裝置描述表
	
	hMemDC = CreateCompatibleDC(hScrDC);				// 為螢幕裝置描述表建立相容的記憶體裝置描述表

	nX = lpRect->left;
	nY = lpRect->top;
	nX2 = lpRect->right;
	nY2 = lpRect->bottom;
	
	xScrn = GetDeviceCaps(hScrDC, HORZRES);	// 獲得螢幕水平解析度
	yScrn = GetDeviceCaps(hScrDC, VERTRES);

	if (nX < 0)
		nX = 0;
	if (nY < 0)
		nY = 0;
	if (nX2 > xScrn)
		nX2 = xScrn;
	if (nY2 > yScrn)
		nY2 = yScrn;
	nWidth = nX2 - nX;
	nHeight = nY2 - nY;

	hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);		// 建立一個與螢幕裝置描述表相容的點陣圖
	hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);			// 把新點陣圖選到記憶體裝置描述表中
	BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);	// 把螢幕裝置描述表拷貝到記憶體裝置描述表中
	hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);			// 得到螢幕點陣圖的控制代碼

	DeleteDC(hScrDC);
	DeleteDC(hMemDC);

	return hBitmap;
}

/*
	lpFileName: 點陣圖檔名
*/
BOOL SaveBitmapToFile(HBITMAP hBitmap, LPSTR lpFileName)
{
	HDC hDC;						// 裝置描述表
	
	int iBits;						// 當前顯示解析度下每個畫素所佔位元組數
	WORD wBitCount;					// 點陣圖中每個畫素所佔位元組數
	DWORD dwPaletteSize = 0, dwBmBitsSize, dwDIBSize, dwWritten;	// 調色盤大小,點陣圖資料大小,點陣圖檔案大小,寫入檔案位元組數
	BITMAP Bitmap;					//點陣圖屬性結構
	BITMAPFILEHEADER bmfHdr;		// 點陣圖檔案頭
	BITMAPINFOHEADER bi;			// 點陣圖資訊頭
	LPBITMAPINFOHEADER lpbi;		// 指向點陣圖資訊頭結構
	
	HANDLE fh, hDib;				// 定義檔案,分配記憶體控制代碼
	HPALETTE hPal, hOldPal=NULL;	// 調色盤控制代碼

	// 計算點陣圖檔案每個畫素所佔位元組數
	hDC = CreateDC("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 if (iBits <= 24)
		wBitCount = 24;
	else
		wBitCount = 32;
	if (wBitCount <= 8)
		dwPaletteSize = (1 << wBitCount) * sizeof(RGBQUAD);		// 計算調色盤大小

	// 設定點陣圖資訊頭結構
	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;

	hDib = GlobalAlloc(GHND, dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));	// 為點陣圖內容分配記憶體
	lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
	*lpbi = bi;
	// 處理調色盤
	hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
	if (hPal)
	{
		hDC = GetDC(NULL);
		hOldPal = SelectPalette(hDC, hPal, FALSE);
		RealizePalette(hDC);
	}
	// 獲取該調色盤下新的畫素值
	GetDIBits(hDC, hBitmap, 0, (UINT)Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) + dwPaletteSize, (BITMAPINFO*)lpbi, DIB_RGB_COLORS);
	
	if (hOldPal)				// 恢復調色盤
	{
		SelectPalette(hDC, 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;
}