我做了程序需要截图发现全屏截图不全。检查获得的分辨率大小1280x720小于真正分辨率1600x900,这是进行了1.25缩放
因为自己显示设置开启了屏幕缩放125%
获取的分辨率不够全屏,是虚拟屏幕的分辨率。所以截图只截取了部分。
有办法获取包括虚拟屏幕、物理屏幕分辨率,还有缩放比例的代码
// 获取窗口当前显示的监视器
HWND hWnd = GetDesktopWindow();//根据需要可以替换成自己程序的句柄
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
// 获取监视器逻辑宽度与高度
MONITORINFOEX miex;
miex.cbSize = sizeof(miex);
GetMonitorInfo(hMonitor, &miex);
int cxLogical = (miex.rcMonitor.right - miex.rcMonitor.left);
int cyLogical = (miex.rcMonitor.bottom - miex.rcMonitor.top);
// 获取监视器物理宽度与高度
DEVMODE dm;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm);
int cxPhysical = dm.dmPelsWidth;
int cyPhysical = dm.dmPelsHeight;
//缩放比例计算
double horzScale = ((double)cxPhysical / (double)cxLogical);
double vertScale = ((double)cyPhysical / (double)cyLogical);之后截图,只需要用到物理显示器的分辨率设置截取大小就行了。一个测试的代码是这个
#include <windows.h>
#include <gdiplus.h>
#include <fstream>
#pragma comment(lib, "gdiplus.lib")
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
UINT num = 0;
UINT size = 0;
Gdiplus::GetImageEncodersSize(&num, &size);
if (size == 0) return -1;
Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
if (pImageCodecInfo == NULL) return -1;
Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);
for (UINT j = 0; j < num; ++j) {
if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free(pImageCodecInfo);
return -1;
}
bool SaveBitmapToFile(HBITMAP hBitmap, const wchar_t* filename) {
Gdiplus::Bitmap bitmap(hBitmap, NULL);
CLSID clsid;
GetEncoderClsid(L"image/png", &clsid);
return bitmap.Save(filename, &clsid, NULL) == Gdiplus::Ok;
}
bool CaptureScreen(const wchar_t* filename) {
// 获取屏幕尺寸
//int screenWidth = GetSystemMetrics(SM_CXSCREEN);
//int screenHeight = GetSystemMetrics(SM_CYSCREEN);
// 获取窗口当前显示的监视器
HWND hWnd = GetDesktopWindow();
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
// 获取监视器逻辑宽度与高度
MONITORINFOEX miex;
miex.cbSize = sizeof(miex);
GetMonitorInfo(hMonitor, &miex);
int cxLogical = (miex.rcMonitor.right - miex.rcMonitor.left);
int cyLogical = (miex.rcMonitor.bottom - miex.rcMonitor.top);
// 获取监视器物理宽度与高度
DEVMODE dm;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm);
int screenWidth = dm.dmPelsWidth;
int screenHeight = dm.dmPelsHeight;
// 获取设备上下文
HDC hScreenDC = GetDC(NULL);
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
// 创建位图
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, screenWidth, screenHeight);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);
// 复制屏幕内容到位图
BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight, hScreenDC, 0, 0, SRCCOPY);
// 恢复并清理
SelectObject(hMemoryDC, hOldBitmap);
// 保存位图
bool result = SaveBitmapToFile(hBitmap, filename);
// 清理资源
DeleteObject(hBitmap);
DeleteDC(hMemoryDC);
ReleaseDC(NULL, hScreenDC);
return result;
}
int main() {
// 初始化GDI+
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// 截图并保存
if (CaptureScreen(L"screenshot.png")) {
printf("save success\n");
} else {
printf("save fail\n");
}
// 关闭GDI+
Gdiplus::GdiplusShutdown(gdiplusToken);
return 0;
}
使用mingw编译需要链接库参数-lgdi32 -lgdiplus,之后运行能够截取到全屏截图并保存到当前目录png文件。
之前用的这2个代码获取的屏幕尺寸在屏幕缩放后就是错的。