当前位置: 首页 > news >正文

C++ Windows下屏幕截图

屏幕截图核心代码(如果要求高帧率,请使用DxGI):

// RGB到YUV的转换公式
#define RGB_TO_Y(r, g, b) ((int)((0.299 * (r)) + (0.587 * (g)) + (0.114 * (b))))
#define RGB_TO_U(r, g, b) ((int)((-0.169 * (r)) - (0.331 * (g)) + (0.500 * (b)) + 128))
#define RGB_TO_V(r, g, b) ((int)((0.500 * (r)) - (0.419 * (g)) - (0.081 * (b)) + 128))

// 假设输入图像是32位ARGB,宽度为width,高度为height,如果是图像是RGB,下面像素位数4改为3即可
void ConvertRGBToYUV420P(unsigned char* rgbData, int width, int height, unsigned char* yuvData)
{
	int ySize = width * height;
	int uvSize = width * height / 4;

	// 填充Y分量
	for (int i = 0; i < height; ++i)
	{
		for (int j = 0; j < width; ++j)
		{
			int index = i * width + j;
			yuvData[index] = RGB_TO_Y(rgbData[index * 4], rgbData[index * 4 + 1], rgbData[index * 4 + 2]);
		}
	}

	// 填充U和V分量(下采样)
	int uvIndex = ySize;
	for (int i = 0; i < height; i += 2)
	{
		for (int j = 0; j < width; j += 2)
		{
			int rgbIndex = i * width + j;
			yuvData[uvIndex++] = RGB_TO_U(rgbData[rgbIndex * 4], rgbData[rgbIndex * 4 + 1], rgbData[rgbIndex * 4 + 2]);
		}
	}

	for (int i = 0; i < height; i += 2)
	{
		for (int j = 0; j < width; j += 2)
		{
			int rgbIndex = i * width + j;
			yuvData[uvIndex++] = RGB_TO_V(rgbData[rgbIndex * 4], rgbData[rgbIndex * 4 + 1], rgbData[rgbIndex * 4 + 2]);
		}
	}
}

void SaveYUV420P(const char* filename, unsigned char* yuvBuffer, int width, int height)
{
	FILE* file = fopen(filename, "wb");
	if (!file)
	{
		AfxMessageBox(_T("Failed to open file for writing!"));
		return;
	}

	int frameSize = width * height * 3 / 2;
	fwrite(yuvBuffer, 1, frameSize, file);
	fclose(file);
}

void SaveHBitmapToBmpFile(HBITMAP hBitmap, CString path)
{
	// 定义文件头结构
	BITMAPFILEHEADER fileHead;
	int fileHeadLen = sizeof(BITMAPFILEHEADER);

	// 定义图象信息结构
	BITMAPINFOHEADER bmpHead;
	int bmpHeadLen = sizeof(BITMAPINFOHEADER);

	// 获取HBITMAP对象信息
	BITMAP bmpObj;
	GetObject(hBitmap, sizeof(BITMAP), &bmpObj);

	// 计算文件总的字节大小
	DWORD fileSizeInByte;
	CDC srcDC;
	srcDC.CreateDC(L"DISPLAY", NULL, NULL, NULL);
	DWORD PixelSizeInBit = srcDC.GetDeviceCaps(BITSPIXEL) * srcDC.GetDeviceCaps(PLANES);
	fileSizeInByte = fileHeadLen + bmpHeadLen + bmpObj.bmWidth * bmpObj.bmHeight * PixelSizeInBit / 8;

	// 初始化文件头结构
	fileHead.bfOffBits = fileHeadLen + bmpHeadLen;
	fileHead.bfReserved1 = 0;
	fileHead.bfReserved2 = 0;
	fileHead.bfSize = fileSizeInByte;
	fileHead.bfType = 0x4D42; // 'BM'

	// 初始图像信息结构
	bmpHead.biBitCount = PixelSizeInBit;
	bmpHead.biClrImportant = 0;
	bmpHead.biClrUsed = 0;
	bmpHead.biCompression = BI_RGB;
	bmpHead.biHeight = -bmpObj.bmHeight;//图像数据颠倒处理
	bmpHead.biPlanes = 1;
	bmpHead.biSize = bmpHeadLen;
	bmpHead.biSizeImage = bmpObj.bmWidth * bmpObj.bmHeight * PixelSizeInBit / 8;
	bmpHead.biWidth = bmpObj.bmWidth;
	bmpHead.biXPelsPerMeter = 0;
	bmpHead.biYPelsPerMeter = 0;

	// 创建并打开BMP文件
	CFile file;
	if (!file.Open(path, CFile::modeCreate | CFile::modeWrite))
	{
		// 处理文件打开失败的情况
		return;
	}

	// 写入文件头和图象信息头
	file.Write(&fileHead, fileHeadLen);
	file.Write(&bmpHead, bmpHeadLen);

	// 获取位图数据并写入文件
	BYTE* pBitmapBits = NULL;
	BITMAPINFO bmpInfo;
	ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
	bmpInfo.bmiHeader = bmpHead;
	
	HDC hDC = GetDC(NULL);
	HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDC, hBitmap);
	pBitmapBits = new unsigned char[bmpHead.biSizeImage];
	int nBits = GetDIBits(hDC, hBitmap, 0, bmpObj.bmHeight, pBitmapBits, &bmpInfo, DIB_RGB_COLORS);
	file.Write(pBitmapBits, bmpHead.biSizeImage);

	// 转换RGB到YUV420P
	unsigned char* yuvBuffer = new unsigned char[bmpObj.bmWidth * bmpObj.bmHeight * 3 / 2];
	ConvertRGBToYUV420P(pBitmapBits, bmpObj.bmWidth, bmpObj.bmHeight, yuvBuffer);
	SaveYUV420P("d:\\a.yuv", yuvBuffer, bmpObj.bmWidth, bmpObj.bmHeight);
	delete[] yuvBuffer;

	// 恢复原来的位图对象并释放资源
	SelectObject(hDC, hOldBitmap);
	ReleaseDC(NULL, hDC);
	delete[] pBitmapBits;

	// 关闭文件
	file.Close();
}

// 获取屏幕截图
HBITMAP CaptureScreen()
{
	HDC hScreen = GetDC(NULL);
	HDC hDC = CreateCompatibleDC(hScreen);

	int width = GetSystemMetrics(SM_CXSCREEN);
	int height = GetSystemMetrics(SM_CYSCREEN);

	HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, width, height);
	SelectObject(hDC, hBitmap);
	BitBlt(hDC, 0, 0, width, height, hScreen, 0, 0, SRCCOPY);

	DeleteDC(hDC);
	ReleaseDC(NULL, hScreen);
	
	return hBitmap;
}

void CaptureAndSaveScreenAsYUV420P(const char* filename)
{
	HBITMAP hBitmap = CaptureScreen();
	SaveHBitmapToBmpFile(hBitmap, _T("d:\\a.bmp"));
	DeleteObject(hBitmap);
}

CaptureAndSaveScreenAsYUV420P("d:\\a.yuv");

该代码包含了抓取屏幕数据获取到HBITMAP对象,并根据HBITMAP对象获取到RGB数据,RGB数据可以保存bmp文件,也可以转换YUV420P后进行图像编码,具体如何使用,各取所需吧。

相关文章:

  • DeepSeek-R1国产化系统gpu驱动+cuda+ollama+webui可视化离线私有化部署
  • 【Python】——使用python实现GUI图书管理系统:Tkinter+SQLite实战
  • 大模型工程师学习日记(十):基于 LangChain 构建向量存储和查询 Qdrant
  • LearnOpenGL——高级光照(中)
  • Kali CentOs 7代理
  • 【JavaEE】-- 多线程(初阶)4
  • 投入与专注
  • 【Pandas】pandas Series replace
  • 【Python/Pytorch】-- 创建3090Ti显卡所需环境
  • 【芯片设计】AI芯片前端设计工程师面试记录·20250303
  • Django:文件上传时报错in a frame because it set ‘X-Frame-Options‘ to ‘deny‘.
  • 魔百盒CM311-1a_YST_晶晨S905L3A芯片_2+8G_安卓9.0_免拆卡刷固件包
  • 不同类型光谱相机的技术差异比较
  • WPF-Avalonia-ReactiveUI-路由实践
  • 【商城实战(1)】启航:从0到1搭建电商帝国的第一步
  • Rust编程实战:Rust实现简单的Web服务,单线程性能问题
  • 第八篇《九变篇》
  • android13打基础: 控件alertdialog
  • 电子电气架构 --- 拓扑架构集中的趋势及其演变
  • Linux12-TCP\HTTP
  • 做投资理财网站/网络营销的5种营销方式
  • 红色网站建设的比较好的高校/北京百度推广开户
  • 网站管理制度规范/seo 的原理和作用
  • 网站开发+兼职挣钱吗/发布平台
  • 推广型网站建设网址/海外seo
  • 怎么替换网站模板/如何快速推广网站