截取全屏幕
#include <windows.h>
void
echo(
CHAR
*str);
int
CaptureImage(
HWND
hWnd,
CHAR
*dirPath,
CHAR
*filename);
int
main()
{
echo(TEXT(
"Ready"
));
CaptureImage(GetDesktopWindow(),
"E:\", "
screen");
// 保存為 E:screen.bmp
echo(TEXT(
"end"
));
return
0;
}
/**
* 調試輸出
*/
void
echo(
CHAR
*str)
{
MessageBox(NULL, str, NULL, MB_OK);
}
/**
* GDI 截屏函數
*
* 參數 hwnd 要截屏的窗口句柄
* 參數 dirPath 截圖存放目錄
* 參數 filename 截圖名稱
*/
int
CaptureImage(
HWND
hwnd,
CHAR
*dirPath,
CHAR
*filename)
{
HANDLE
hDIB;
HANDLE
hFile;
DWORD
dwBmpSize;
DWORD
dwSizeofDIB;
DWORD
dwBytesWritten;
CHAR
FilePath[MAX_PATH];
HBITMAP
hbmScreen = NULL;
BITMAP bmpScreen;
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
CHAR
*lpbitmap;
INT
width = GetSystemMetrics(SM_CXSCREEN);
// 屏幕寬
INT
height = GetSystemMetrics(SM_CYSCREEN);
// 屏幕高
HDC
hdcScreen = GetDC(NULL);
// 全屏幕DC
HDC
hdcMemDC = CreateCompatibleDC(hdcScreen);
// 創建兼容內存DC
if
(!hdcMemDC)
{
echo(TEXT(
"CreateCompatibleDC has failed"
));
goto
done;
}
// 通過窗口DC 創建一個兼容位圖
hbmScreen = CreateCompatibleBitmap(hdcScreen, width, height);
if
(!hbmScreen)
{
echo(TEXT(
"CreateCompatibleBitmap Failed"
));
goto
done;
}
// 將位圖塊傳送到我們兼容的內存DC中
SelectObject(hdcMemDC, hbmScreen);
if
(!BitBlt(
hdcMemDC,
// 目的DC
0, 0,
// 目的DC的 x,y 坐標
width, height,
// 目的 DC 的寬高
hdcScreen,
// 來源DC
0, 0,
// 來源DC的 x,y 坐標
SRCCOPY))
// 粘貼方式
{
echo(TEXT(
"BitBlt has failed"
));
goto
done;
}
// 獲取位圖信息並存放在 bmpScreen 中
GetObject(hbmScreen,
sizeof
(BITMAP), &bmpScreen);
bi.biSize =
sizeof
(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
// 在 32-bit Windows 系統上, GlobalAlloc 和 LocalAlloc 是由 HeapAlloc 封裝來的
// handle 指向進程默認的堆. 所以開銷比 HeapAlloc 要大
hDIB = GlobalAlloc(GHND, dwBmpSize);
lpbitmap = (
char
*)GlobalLock(hDIB);
// 獲取兼容位圖的位並且拷貝結果到一個 lpbitmap 中.
GetDIBits(
hdcScreen,
// 設備環境句柄
hbmScreen,
// 位圖句柄
0,
// 指定檢索的第一個掃描線
(
UINT
)bmpScreen.bmHeight,
// 指定檢索的掃描線數
lpbitmap,
// 指向用來檢索位圖數據的緩沖區的指針
(BITMAPINFO *)&bi,
// 該結構體保存位圖的數據格式
DIB_RGB_COLORS
// 顏色表由紅、綠、藍(RGB)三個直接值構成
);
wsprintf(FilePath,
"%s\%s.bmp"
, dirPath, filename);
// 創建一個文件來保存文件截圖
hFile = CreateFile(
FilePath,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
// 將 圖片頭(headers)的大小, 加上位圖的大小來獲得整個文件的大小
dwSizeofDIB = dwBmpSize +
sizeof
(BITMAPFILEHEADER) +
sizeof
(BITMAPINFOHEADER);
// 設置 Offset 偏移至位圖的位(bitmap bits)實際開始的地方
bmfHeader.bfOffBits = (
DWORD
)
sizeof
(BITMAPFILEHEADER) + (
DWORD
)
sizeof
(BITMAPINFOHEADER);
// 文件大小
bmfHeader.bfSize = dwSizeofDIB;
// 位圖的 bfType 必須是字符串 "BM"
bmfHeader.bfType = 0x4D42;
//BM
dwBytesWritten = 0;
WriteFile(hFile, (
LPSTR
)&bmfHeader,
sizeof
(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (
LPSTR
)&bi,
sizeof
(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (
LPSTR
)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
// 解鎖堆內存並釋放
GlobalUnlock(hDIB);
GlobalFree(hDIB);
// 關閉文件句柄
CloseHandle(hFile);
// 清理資源
done:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL, hdcScreen);
return
0;
}
/**
*其實這樣截取出來的圖片會過大,而且效率也不是很高,如果要改善這個情況的話,需要重新寫一
*個拷貝函數,因為沒有必要每一個顏色(bit)全都拷貝出來,過濾到很多再拷貝的話程序效率會更高,
*而且圖片也會更小,唯一就是圖片質量可能會下降。
*/
截取指定窗口
#include <windows.h>
void
echo(
CHAR
*str);
int
CaptureImage(
HWND
hWnd,
CHAR
*dirPath,
CHAR
*filename);
int
main()
{
echo(
"准備截圖"
);
CaptureImage(GetDesktopWindow(),
"E:\", "
hello");
// 保存為 E:hello.bmp
echo(
"截圖結束"
);
return
0;
}
/**
* 調試輸出
*/
void
echo(
CHAR
*str)
{
MessageBox(NULL, str, NULL, MB_OK);
}
/**
* GDI 截取指定窗口
*
* 參數 hwnd 要截屏的窗口句柄
* 參數 dirPath 截圖存放目錄
* 參數 filename 截圖名稱
*/
int
CaptureImage(
HWND
hwnd,
CHAR
*dirPath,
CHAR
*filename)
{
HDC
mdc;
HBITMAP
hbmp;
CHAR
FilePath[MAX_PATH];
HDC
hdcScreen;
HDC
hdcWindow;
HDC
hdcMemDC = NULL;
HBITMAP
hbmScreen = NULL;
BITMAP bmpScreen;
RECT rcClient;
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
DWORD
dwBmpSize;
HANDLE
hDIB;
CHAR
*lpbitmap;
HANDLE
hFile;
DWORD
dwSizeofDIB;
DWORD
dwBytesWritten;
hdcScreen = GetDC(NULL);
// 全屏幕DC
hdcWindow = GetDC(hwnd);
// 截圖目標窗口DC
// 創建兼容內存DC
hdcMemDC = CreateCompatibleDC(hdcWindow);
if
(!hdcMemDC)
{
echo(TEXT(
"CreateCompatibleDC has failed"
));
goto
done;
}
// 獲取客戶端區域用於計算大小
GetClientRect(hwnd, &rcClient);
// 設置延展模式
SetStretchBltMode(hdcWindow, HALFTONE);
// 來源 DC 是整個屏幕而目標 DC 是當前的窗口 (HWND)
if
(!StretchBlt(hdcWindow,
0,0,
rcClient.right, rcClient.bottom,
hdcScreen,
0,0,
GetSystemMetrics (SM_CXSCREEN),
GetSystemMetrics (SM_CYSCREEN),
SRCCOPY))
{
echo(TEXT(
"StretchBlt has failed"
));
goto
done;
}
// 通過窗口DC 創建一個兼容位圖
hbmScreen = CreateCompatibleBitmap(
hdcWindow,
rcClient.right-rcClient.left,
rcClient.bottom-rcClient.top
);
if
(!hbmScreen)
{
echo(TEXT(
"CreateCompatibleBitmap Failed"
));
goto
done;
}
// 將位圖塊傳送到我們兼容的內存DC中
SelectObject(hdcMemDC,hbmScreen);
if
(!BitBlt(
hdcMemDC,
// 目的DC
0,0,
// 目的DC的 x,y 坐標
rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
// 目的 DC 的寬高
hdcWindow,
// 來源DC
0,0,
// 來源DC的 x,y 坐標
SRCCOPY))
// 粘貼方式
{
echo(TEXT(
"BitBlt has failed"
));
goto
done;
}
// 獲取位圖信息並存放在 bmpScreen 中
GetObject(hbmScreen,
sizeof
(BITMAP),&bmpScreen);
bi.biSize =
sizeof
(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
// 在 32-bit Windows 系統上, GlobalAlloc 和 LocalAlloc 是由 HeapAlloc 封裝來的
// handle 指向進程默認的堆. 所以開銷比 HeapAlloc 要大
hDIB = GlobalAlloc(GHND,dwBmpSize);
lpbitmap = (
char
*)GlobalLock(hDIB);
// 獲取兼容位圖的位並且拷貝結果到一個 lpbitmap 中.
GetDIBits(
hdcWindow,
// 設備環境句柄
hbmScreen,
// 位圖句柄
0,
// 指定檢索的第一個掃描線
(
UINT
)bmpScreen.bmHeight,
// 指定檢索的掃描線數
lpbitmap,
// 指向用來檢索位圖數據的緩沖區的指針
(BITMAPINFO *)&bi,
// 該結構體保存位圖的數據格式
DIB_RGB_COLORS
// 顏色表由紅、綠、藍(RGB)三個直接值構成
);
wsprintf(FilePath,
"%s\%s.bmp"
, dirPath, filename);
// 創建一個文件來保存文件截圖
hFile = CreateFile(
FilePath,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
// 將 圖片頭(headers)的大小, 加上位圖的大小來獲得整個文件的大小
dwSizeofDIB = dwBmpSize +
sizeof
(BITMAPFILEHEADER) +
sizeof
(BITMAPINFOHEADER);
// 設置 Offset 偏移至位圖的位(bitmap bits)實際開始的地方
bmfHeader.bfOffBits = (
DWORD
)
sizeof
(BITMAPFILEHEADER) + (
DWORD
)
sizeof
(BITMAPINFOHEADER);
// 文件大小
bmfHeader.bfSize = dwSizeofDIB;
// 位圖的 bfType 必須是字符串 "BM"
bmfHeader.bfType = 0x4D42;
//BM
dwBytesWritten = 0;
WriteFile(hFile, (
LPSTR
)&bmfHeader,
sizeof
(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (
LPSTR
)&bi,
sizeof
(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (
LPSTR
)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
// 解鎖堆內存並釋放
GlobalUnlock(hDIB);
GlobalFree(hDIB);
// 關閉文件句柄
CloseHandle(hFile);
// 清理資源
done:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL,hdcScreen);
ReleaseDC(hwnd,hdcWindow);
return
0;
}