Windows API 读取屏幕图像(截图)
获取屏幕尺寸
1GetSystemMetrics(SM_CXSCREEN); // 获取主显示器的逻辑宽度
2GetSystemMetrics(SM_CYSCREEN); // 获取主显示器的逻辑高度或
1GetSystemMetrics(SM_CXVIRTUALSCREEN); // 获取虚拟屏幕的逻辑宽度
2GetSystemMetrics(SM_CXVIRTUALSCREEN); // 获取虚拟屏幕的逻辑高度如果开启了屏幕缩放,则可以调用以下代码忽略屏幕缩放:
1// 忽略缩放
2SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);读取屏幕的图像
1// 获取屏幕设备上下文
2HDC hScreenDC = GetDC(NULL);
3
4// 创建兼容指定设备的内存设备上下文
5HDC hMemDC = CreateCompatibleDC(hScreenDC);
6
7// 创建兼容指定设备上下文的位图
8HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);
9
10// 绑定内存设备上下文和位图
11SelectObject(hMemDC, hBitmap);
12
13// 将屏幕图像读取到内存设备上下文
14BitBlt(hMemDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY | CAPTUREBLT);从图像中读取像素
1// 创建位图的 Info Header
2BITMAPINFOHEADER bi = {0};
3bi.biSize = sizeof(BITMAPINFOHEADER);
4bi.biWidth = width;
5bi.biHeight = -height; // 屏幕原点在左上角,位图原点在左下角
6bi.biPlanes = 1;
7bi.biBitCount = 24; // 使用 24 位颜色,注意:颜色顺序是 BGR
8bi.biCompression = BI_RGB;
9
10// 读取像素
11int lineBytes = ((bi.biWidth * bi.biBitCount + 31) / 32) * 4; // 四字节对齐
12int imageSize = lineBytes * height;
13BYTE* pixels = malloc(imageSize);
14GetDIBits(hMemDC, hBitmap, 0, height, pixels, (BITMAPINFO*)&bi, DIB_RGB_COLORS);注意:BMP 的像素每行都按 4 字节对齐,并且颜色顺序是 BGR。
完整示例
1#include <stdio.h>
2#include <Windows.h>
3
4// 使用 MinGW 时需要添加 -lgdi32 选项
5#pragma comment(lib, "gbi32.lib")
6
7int main()
8{
9 // 获取虚拟屏幕尺寸
10 int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
11 int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
12
13 // 获取屏幕设备上下文
14 HDC hScreenDC = GetDC(NULL);
15
16 // 创建兼容指定设备的内存设备上下文
17 HDC hMemDC = CreateCompatibleDC(hScreenDC);
18
19 // 创建兼容指定设备上下文的位图
20 HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);
21
22 // 绑定内存设备上下文和位图
23 SelectObject(hMemDC, hBitmap);
24
25 // 将屏幕图像读取到内存设备上下文
26 BitBlt(hMemDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY | CAPTUREBLT);
27
28 // 创建位图的 Info Header
29 BITMAPINFOHEADER bi = {0};
30 bi.biSize = sizeof(BITMAPINFOHEADER);
31 bi.biWidth = width;
32 bi.biHeight = -height; // 屏幕原点在左上角,位图原点在左下角
33 bi.biPlanes = 1;
34 bi.biBitCount = 24; // 使用 24 位颜色,注意:颜色顺序是 BGR
35 bi.biCompression = BI_RGB;
36
37 // 读取像素
38 int lineBytes = ((bi.biWidth * bi.biBitCount + 31) / 32) * 4; // 四字节对齐
39 int imageSize = lineBytes * height;
40 BYTE* pixels = malloc(imageSize);
41 GetDIBits(hMemDC, hBitmap, 0, height, pixels, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
42
43 // 创建位图的 File Header
44 BITMAPFILEHEADER bf = {0};
45 bf.bfType = 0x4D42; // 'BM'
46 bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
47 bf.bfSize = bf.bfOffBits + imageSize;
48
49 // 写入文件
50 FILE* fp = fopen("save.bmp", "wb");
51 fwrite(&bf, sizeof(bf), 1, fp);
52 fwrite(&bi, sizeof(bi), 1, fp);
53 fwrite(pixels, imageSize, 1, fp);
54 fclose(fp);
55
56 // 释放资源
57 free(pixels);
58 DeleteObject(hBitmap);
59 DeleteDC(hMemDC);
60 ReleaseDC(NULL, hScreenDC);
61 return 0;
62}