C++ Dxgi快速截屏并保存为rgb格式和bmp格式完整示例代码


/**
* @author wh445306
* @version 1.0
* @Description C++ Dxgi截屏并保存为rgb格式和bmp格式完整示例代码
* @Date 2022-09-25 20:46
*/


#include <d3d11.h>
#include <dxgi1_2.h>
#include <stdio.h>

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")

#pragma warning(disable:4996)



// 将RGB格式图片转成bmp格式
void RGBDataSaveAsBmpFile(
	const char * bmpFile,                // BMP文件名称
	unsigned char * pRgbData,            // 图像数据
	int width,                           // 图像宽度  
	int height,                          // 图像高度
	int biBitCount,                      // 位图深度
	bool flipvertical)                   // 图像是否需要垂直翻转
{
	int size = 0;
	int bitsPerPixel = 3;
	if (biBitCount == 24)
	{
		bitsPerPixel = 3;
		size = width * height * bitsPerPixel * sizeof(char); // 每个像素点3个字节
	}
	else if (biBitCount == 32)
	{
		bitsPerPixel = 4;
		size = width * height * bitsPerPixel * sizeof(char); // 每个像素点4个字节
	}
	else return;

	// 位图第一部分,文件信息  
	BITMAPFILEHEADER bfh;
	bfh.bfType = (WORD)0x4d42;  //图像格式 必须为'BM'格式
	bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);//真正的数据的位置
	bfh.bfSize = size + bfh.bfOffBits;
	bfh.bfReserved1 = 0;
	bfh.bfReserved2 = 0;

	BITMAPINFOHEADER bih;
	bih.biSize = sizeof(BITMAPINFOHEADER);
	bih.biWidth = width;
	if (flipvertical)
		bih.biHeight = -height;//BMP图片从最后一个点开始扫描,显示时图片是倒着的,所以用-height,这样图片就正了  
	else
		bih.biHeight = height;
	bih.biPlanes = 1;
	bih.biBitCount = biBitCount;
	bih.biCompression = BI_RGB;
	bih.biSizeImage = size;
	bih.biXPelsPerMeter = 0;
	bih.biYPelsPerMeter = 0;
	bih.biClrUsed = 0;
	bih.biClrImportant = 0;
	FILE * fp = NULL;
	fopen_s(&fp, bmpFile, "wb");
	if (!fp)
		return;

	fwrite(&bfh, 8, 1, fp);
	fwrite(&bfh.bfReserved2, sizeof(bfh.bfReserved2), 1, fp);
	fwrite(&bfh.bfOffBits, sizeof(bfh.bfOffBits), 1, fp);
	fwrite(&bih, sizeof(BITMAPINFOHEADER), 1, fp);
	fwrite(pRgbData, size, 1, fp);
	fclose(fp);
}



int main()
{
	HRESULT hr;
	// Driver types supported 支持的驱动程序类型
	D3D_DRIVER_TYPE DriverTypes[] =
	{
		D3D_DRIVER_TYPE_HARDWARE,
		D3D_DRIVER_TYPE_WARP,
		D3D_DRIVER_TYPE_REFERENCE,
	};

	UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
	// Feature levels supported 支持的功能级别
	D3D_FEATURE_LEVEL FeatureLevels[] =
	{
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_10_0,
		D3D_FEATURE_LEVEL_9_1
	};

	UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);

	D3D_FEATURE_LEVEL FeatureLevel;

	ID3D11Device *_pDX11Dev = nullptr;
	ID3D11DeviceContext *_pDX11DevCtx = nullptr;

	// Create D3D device 创建D3D设备
	for (UINT index = 0; index < NumDriverTypes; index++)
	{
		hr = D3D11CreateDevice(nullptr,
			DriverTypes[index],
			nullptr, 0,
			FeatureLevels,
			NumFeatureLevels,
			D3D11_SDK_VERSION,
			&_pDX11Dev,
			&FeatureLevel,
			&_pDX11DevCtx);

		if (SUCCEEDED(hr)) {
			break;
		}
	}

	IDXGIDevice *_pDXGIDev = nullptr;
	// Get DXGI device 获取 DXGI 设备
	hr = _pDX11Dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&_pDXGIDev));
	if (FAILED(hr)) {
		return false;
	}

	IDXGIAdapter *_pDXGIAdapter = nullptr;
	// Get DXGI adapter 获取 DXGI 适配器
	hr = _pDXGIDev->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&_pDXGIAdapter));
	if (FAILED(hr)) {
		return false;
	}

	UINT i = 0;
	IDXGIOutput *_pDXGIOutput = nullptr;
	// Get output 获取输出
	hr = _pDXGIAdapter->EnumOutputs(i, &_pDXGIOutput);
	if (FAILED(hr)) {
		return false;
	}

	DXGI_OUTPUT_DESC DesktopDesc;
	// Get output description struct 获取输出描述结构
	_pDXGIOutput->GetDesc(&DesktopDesc);

	IDXGIOutput1 *_pDXGIOutput1 = nullptr;
	// QI for Output1 请求接口给Output1
	hr = _pDXGIOutput->QueryInterface(__uuidof(IDXGIOutput1), reinterpret_cast<void**>(&_pDXGIOutput1));
	if (FAILED(hr)) {
		return false;
	}

	IDXGIOutputDuplication *_pDXGIOutputDup = nullptr;
	// Create desktop duplication 创建桌面副本
	hr = _pDXGIOutput1->DuplicateOutput(_pDX11Dev, &_pDXGIOutputDup);
	if (FAILED(hr)) {
		return false;
	}

	for (int i = 0; i < 3; i++)
	{
		IDXGIResource *desktopResource = nullptr;
		DXGI_OUTDUPL_FRAME_INFO frameInfo;
		hr = _pDXGIOutputDup->AcquireNextFrame(20, &frameInfo, &desktopResource);
		if (FAILED(hr))
		{
			if (hr == DXGI_ERROR_WAIT_TIMEOUT)
			{
				if (desktopResource) {
					desktopResource->Release();
					desktopResource = nullptr;
				}
				hr = _pDXGIOutputDup->ReleaseFrame();
			}
			else
			{
				return false;
			}
		}

		ID3D11Texture2D *_pDX11Texture = nullptr;
		// query next frame staging buffer 查询下一帧暂存缓冲区
		hr = desktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&_pDX11Texture));
		desktopResource->Release();
		desktopResource = nullptr;
		if (FAILED(hr)) {
			return false;
		}

		ID3D11Texture2D *_pCopyBuffer = nullptr;

		D3D11_TEXTURE2D_DESC desc;
		// copy old description 复制旧描述
		if (_pDX11Texture)
		{
			_pDX11Texture->GetDesc(&desc);
		}
		else if (_pCopyBuffer)
		{
			_pCopyBuffer->GetDesc(&desc);
		}
		else
		{
			return false;
		}

		// create a new staging buffer for fill frame image 为填充帧图像创建一个新的暂存缓冲区
		if (_pCopyBuffer == nullptr) {
			D3D11_TEXTURE2D_DESC CopyBufferDesc;
			CopyBufferDesc.Width = desc.Width;
			CopyBufferDesc.Height = desc.Height;
			CopyBufferDesc.MipLevels = 1;
			CopyBufferDesc.ArraySize = 1;
			CopyBufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
			CopyBufferDesc.SampleDesc.Count = 1;
			CopyBufferDesc.SampleDesc.Quality = 0;
			CopyBufferDesc.Usage = D3D11_USAGE_STAGING;
			CopyBufferDesc.BindFlags = 0;
			CopyBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
			CopyBufferDesc.MiscFlags = 0;

			hr = _pDX11Dev->CreateTexture2D(&CopyBufferDesc, nullptr, &_pCopyBuffer);
			if (FAILED(hr)) {
				return false;
			}
		}

		if (_pDX11Texture)
		{
			// copy next staging buffer to new staging buffer 将下一个暂存缓冲区复制到新的暂存缓冲区
			_pDX11DevCtx->CopyResource(_pCopyBuffer, _pDX11Texture);
		}

		IDXGISurface *CopySurface = nullptr;
		// create staging buffer for map bits 为映射位创建暂存缓冲区
		hr = _pCopyBuffer->QueryInterface(__uuidof(IDXGISurface), (void **)&CopySurface);
		if (FAILED(hr)) {
			return false;
		}

		DXGI_MAPPED_RECT MappedSurface;
		// copy bits to user space 将位复制到用户空间
		hr = CopySurface->Map(&MappedSurface, DXGI_MAP_READ);

		char picName[128] = { 0 };
		snprintf(picName, sizeof(picName), "Screen%d.rgb", i);
		FILE *p = fopen(picName, "wb");


		if (SUCCEEDED(hr))
		{
			for (int i = 0; i < 1080; ++i)
			{
				fwrite(MappedSurface.pBits + i * MappedSurface.Pitch, 1, MappedSurface.Pitch, p);
			}
			CopySurface->Unmap();
		}

		fclose(p);


		//保存为bmp格式
		char picNameB[128] = { 0 };
		snprintf(picNameB, sizeof(picNameB), "Screen%d.bmp", i);
		RGBDataSaveAsBmpFile(picNameB, MappedSurface.pBits, 1920, 1080, 32, true);


		CopySurface->Unmap();
		hr = CopySurface->Release();
		CopySurface = nullptr;

		if (_pDXGIOutputDup)
		{
			hr = _pDXGIOutputDup->ReleaseFrame();
		}
		//Sleep(1000);
	}

	return 0;
}

效果如下:

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
很抱歉,作为AI语言模型,我无法为您提供编写代码的实际指导。但是,我可以为您提供参考资源和示例代码,供您参考学习和应用。 以下是用Qt和DXGI进行屏幕截图并保存示例代码: ```c++ // Qt 5.x and later with DirectX 11 QPixmap grab() { ID3D11Device* device = nullptr; ID3D11DeviceContext* context = nullptr; IDXGIOutputDuplication* duplication = nullptr; IDXGIResource* resource = nullptr; QPixmap pixmap; QPixmap screenshot; RECT rect = { 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) }; if (SUCCEEDED(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &device, nullptr, &context))) { duplication = GetDuplication(device, context); if (duplication == nullptr) { return pixmap; } DXGI_OUTDUPL_FRAME_INFO frame_info; ID3D11Texture2D* texture = nullptr; D3D11_TEXTURE2D_DESC texture_desc; ZeroMemory(&texture_desc, sizeof(texture_desc)); texture_desc.Width = rect.right - rect.left; texture_desc.Height = rect.bottom - rect.top; texture_desc.MipLevels = 1; texture_desc.ArraySize = 1; texture_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; texture_desc.SampleDesc.Count = 1; texture_desc.Usage = D3D11_USAGE_STAGING; texture_desc.BindFlags = 0; texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; texture_desc.MiscFlags = 0; if (FAILED(device->CreateTexture2D(&texture_desc, nullptr, &texture))) { duplication->Release(); device->Release(); context->Release(); return pixmap; } POINT offset = { rect.left, rect.top }; duplication->GetFramePointer(&frame_info, &texture, &offset); if (FAILED(texture->QueryInterface(IID_PPV_ARGS(&resource)))) { duplication->ReleaseFrame(); duplication->Release(); device->Release(); context->Release(); texture->Release(); return pixmap; } D3D11_MAPPED_SUBRESOURCE map_info; ZeroMemory(&map_info, sizeof(map_info)); if (FAILED(context->Map(texture, 0, D3D11_MAP_READ, 0, &map_info))) { duplication->ReleaseFrame(); duplication->Release(); device->Release(); context->Release(); texture->Release(); resource->Release(); return pixmap; } screenshot = QPixmap::fromImage(QImage(static_cast<uchar*>(map_info.pData), texture_desc.Width, texture_desc.Height, QImage::Format_ARGB32)); pixmap = screenshot.copy(rect); context->Unmap(texture, 0); duplication->ReleaseFrame(); duplication->Release(); device->Release(); context->Release(); texture->Release(); resource->Release(); } return pixmap; } IDXGIOutputDuplication* GetDuplication(ID3D11Device* device, ID3D11DeviceContext* context) { IDXGIOutputDuplication* duplication = nullptr; IDXGIAdapter* adapter = nullptr; IDXGIOutput* output = nullptr; DXGI_OUTPUT_DESC output_desc; ZeroMemory(&output_desc, sizeof(output_desc)); output_desc.Flags = DXGI_ENUMERATION_FLAG_PRIMARY; if (FAILED(CreateDXGIFactory(IID_PPV_ARGS(&factory)))) return nullptr; if (FAILED(factory->EnumAdapters(0, &adapter))) return nullptr; if (FAILED(adapter->EnumOutputs(0, &output))) return nullptr; if (FAILED(output->GetDesc(&output_desc))) return nullptr; D3D11_RENDER_TARGET_VIEW_DESC target_desc; ZeroMemory(&target_desc, sizeof(target_desc)); target_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; ID3D11Texture2D* texture = nullptr; if (FAILED(device->CreateTexture2D(&GetTargetDesc(output_desc.DesktopCoordinates), nullptr, &texture))) return nullptr; ID3D11RenderTargetView* target = nullptr; ID3D11Texture2D* backbuffer = nullptr; D3D11_TEXTURE2D_DESC desc; backbuffer->GetDesc(&desc); target_desc.Texture2D.MipSlice = 0; if (FAILED(device->CreateRenderTargetView(backbuffer, &target_desc, &target))) return nullptr; ID3D11Texture2D* stage_texture = nullptr; if (FAILED(device->CreateTexture2D(&desc, nullptr, &stage_texture))) return nullptr; ID3D11Device* device2 = nullptr; if (FAILED(device->QueryInterface(IID_PPV_ARGS(&device2)))) return nullptr; ID3D11DeviceContext* context2 = nullptr; if (FAILED(device2->CreateDeferredContext(0, &context2))) return nullptr; context2->CopyResource(stage_texture, backbuffer); context2->Flush(); DXGI_OUTPUT_DESC output_desc2; ZeroMemory(&output_desc2, sizeof(output_desc2)); output_desc2.Flags = DXGI_ENUMERATION_FLAG_PRIMARY; IDXGIOutput5* output2 = nullptr; adapter->EnumOutputs(0, (IDXGIOutput**)&output2); output2->DuplicateOutput(context, &duplication); return duplication; } ``` 此代码是用 C++ 和 Qt 框架实现的。如果您非常熟悉Qt和DXGI,那么您可能会发现此代码可能有些错误或漏洞,但这个示例应该可以为您提供一个很好的起点。请确保在尝试使用这段代码之前认真阅读并理解它,并仔细检查以确保它适合您的具体用例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值