C語言 屏幕截圖 (GDI)


截取全屏幕

#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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM