下面是一段屏幕拷貝的代碼,共兩個功能函數,其中一個函數可以把 HBITMAP 保存為 BMP 文件
// scr2bmp.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
LRESULT CALLBACKAbout(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
HBITMAP WINAPIcopyScreenToBitmap(LPRECT lpRect);
BOOL WINAPIsaveBitmapToFile(HBITMAP hBitmap,LPSTR lpFileName);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
DialogBox(hInstance,(LPCTSTR)IDD_ABOUTBOX,NULL,(DLGPROC)About);
return 0;
}
LRESULT CALLBACK About(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
RECTrc;
switch(uMsg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
GetWindowRect(hwnd,&rc);
saveBitmapToFile(copyScreenToBitmap(&rc),"D:\\1.bmp");
EndDialog(hwnd,LOWORD(wParam));
break;
case IDCANCEL:
EndDialog(hwnd,LOWORD(wParam));
break;
}
return TRUE;
}
return FALSE;
}
HBITMAP WINAPI copyScreenToBitmap(LPRECT lpRect)// lpRect 代表選定區域
{
HDChScrDC, hMemDC;// 屏幕和內存設備描述表
HBITMAPhBitmap,hOldBitmap;// 位圖句柄
intnX, nY, nX2, nY2;// 選定區域坐標
intnWidth, nHeight;// 位圖寬度和高度
intxScrn, 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;
}
BOOL WINAPI saveBitmapToFile(HBITMAP hBitmap,// hBitmap 為剛才的屏幕位圖句柄
LPSTR lpFileName)// lpFileName 為位圖文件名
{
HDChDC;// 設備描述表
intiBits;// 當前顯示分辨率下每個像素所占字節數
WORDwBitCount;// 位圖中每個像素所占字節數
DWORDdwPaletteSize = 0,// 定義調色板大小
dwBmBitsSize,// 位圖中像素字節大小
dwDIBSize,// 位圖文件大小
dwWritten;// 寫入文件字節數
BITMAPBitmap;// 位圖屬性結構
BITMAPFILEHEADERbmfHdr;// 位圖文件頭結構
BITMAPINFOHEADERbi;// 位圖信息頭結構
LPBITMAPINFOHEADERlpbi;// 指向位圖信息頭結構
HANDLEfh,// 定義文件
hDib,// 分配內存句柄
hPal;// 調色板句柄
HPALETTEhOldPal = 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 = 24;
// 計算調色板大小
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 = GetStockObject(DEFAULT_PALETTE);
if(hPal)
{
hDC = GetDC(NULL);
hOldPal = SelectPalette(hDC,(HPALETTE)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;
}
/////////////////////////////////////////////////////////////////////////////////////////////
CPaintDC dc(this);
CDC cdcMem;
CBitmap m_bitmap;
cdcMem.CreateCompatibleDC(&dc);
m_bitmap.CreateCompatibleBitmap(&cdcMem, 100, 100);
cdcMem.SelectObject(&m_bitmap);
cdcMem.LineXY(100,100);
在上面代碼中,象訪問數組一樣訪問cdcMem的內存塊,并取得象素的數據,該如何操作?
//////////////////////////////////////////////////////
// 獲取位圖信息大小
BITMAPINFO bmpInfo;
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
int nRet = GetDIBits(dc.m_hDC, m_bitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS);
if (nRet == 0)
{
return;
}
if (bmpInfo.bmiHeader.biSizeImage <= 0)
{
bmpInfo.bmiHeader.biSizeImage = bmpInfo.bmiHeader.biWidth * abs (bmpInfo.bmiHeader.biHeight) * (bmpInfo.bmiHeader.biBitCount+7)/8;
}
// 開辟位圖數據占用的空間
LPVOID lpvBits = malloc(bmpInfo.bmiHeader.biSizeImage);
if (lpvBits == NULL)
{
return;
}
// 獲取位圖數據信息
bmpInfo.bmiHeader.biCompression = BI_RGB;
nRet = GetDIBits(hDC, hBitmap, 0, bmpInfo.bmiHeader.biHeight, lpvBits, &bmpInfo, DIB_RGB_COLORS);
if (nRet == 0)
{
return;
}
// 對位圖信息lpvBits的操作。。。。。
// ......
// 釋放開辟的空間
free(lpvBits);
lpvBits = NULL;