加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

将Windows截图捕获位图渲染为DirectX纹理

发布时间:2020-12-14 05:43:24 所属栏目:Windows 来源:网络整理
导读:我正在开发一个’3d桌面’directx应用程序,它需要在directx(11)的矩形表面上显示桌面窗口的当前内容(例如“计算器”)作为2D纹理.我太近了,但真的很难用屏幕截图BMP – Texture2D步骤.我确实有截图 – HBITMAP和DDSFile-渲染纹理成功工作但无法完成屏幕截图
我正在开发一个’3d桌面’directx应用程序,它需要在directx(11)的矩形表面上显示桌面窗口的当前内容(例如“计算器”)作为2D纹理.我太近了,但真的很难用屏幕截图BMP – > Texture2D步骤.我确实有截图 – > HBITMAP和DDSFile->渲染纹理成功工作但无法完成屏幕截图 – >渲染纹理.

到目前为止,我已经将’抓住窗口作为截图’工作了:

RECT user_window_rectangle;
HWND user_window = FindWindow(NULL,TEXT("Calculator"));
GetClientRect(user_window,&user_window_rectangle);
HDC hdcScreen = GetDC(NULL);
HDC hdc = CreateCompatibleDC(hdcScreen);
UINT screenshot_width = user_window_rectangle.right - user_window_rectangle.left;
UINT screenshot_height = user_window_rectangle.bottom - user_window_rectangle.top;
hbmp = CreateCompatibleBitmap(hdcScreen,screenshot_width,screenshot_height);
SelectObject(hdc,hbmp);
PrintWindow(user_window,hdc,PW_CLIENTONLY);

此时我有HBITMAP hbmp引用的窗口位图.

另外我的代码是将DDS文件渲染为directx / 3d矩形上的纹理:

ID3D11Device *dev;
ID3D11DeviceContext *dev_context;
...
dev_context->PSSetShaderResources(0,1,&shader_resource_view);
dev_context->PSSetSamplers(0,&tex_sampler_state);
...
DirectX::TexMetadata tex_metadata;
DirectX::ScratchImage image;

hr = LoadFromDDSFile(L"Earth.dds",DirectX::DDS_FLAGS_NONE,&tex_metadata,image);
hr = CreateShaderResourceView(dev,image.GetImages(),image.GetImageCount(),tex_metadata,&shader_resource_view);

像素着色器是:

Texture2D ObjTexture
SamplerState ObjSamplerState
float4 PShader(float4 pos : SV_POSITION,float4 color : COLOR,float2 tex : TEXCOORD) : SV_TARGET
{
    return ObjTexture.Sample( ObjSamplerState,tex );
}

samplerstate(默认为线性)是:

D3D11_SAMPLER_DESC sampler_desc;
ZeroMemory(&sampler_desc,sizeof(sampler_desc));
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampler_desc.MinLOD = 0;
sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;

hr = dev->CreateSamplerState(&sampler_desc,&tex_sampler_state);

问题:如何将一个等效的LoadFromDDSFile位替换为从Windows屏幕截图中获取HBITMAP并在显卡上以ObjTexture结束?

下面是我从屏幕截图HBITMAP hbmp桥接到着色器资源screenshot_texture的最佳镜头,但是它给出了图形驱动程序的内存访问冲突(我认为由于我的“data.pSysmem =& bmp.bmBits”,但不知道真):

GetObject(hbmp,sizeof(BITMAP),(LPSTR)&bmp)

D3D11_TEXTURE2D_DESC screenshot_desc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM,bmp.bmWidth,bmp.bmHeight,D3D11_BIND_SHADER_RESOURCE
    );

int bytes_per_pixel = 4;

D3D11_SUBRESOURCE_DATA data;
ZeroMemory(&data,sizeof(D3D11_SUBRESOURCE_DATA));
data.pSysMem = &bmp.bmBits; //pixel buffer
data.SysMemPitch = bytes_per_pixel * bmp.bmWidth;// line size in byte
data.SysMemSlicePitch = bytes_per_pixel * bmp.bmWidth * bmp.bmHeight;// total buffer size in byte

hr = dev->CreateTexture2D(
    &screenshot_desc,//texture format
    &data,// pixel buffer use to fill the texture
    &screenshot_texture  // created texture
    );

:::::::::::::::::::::::::解:::::::::::::::::::::::: ::::::::::::::::::

主要问题是尝试直接使用& bmp.bmBits作为像素缓冲区导致图形驱动程序内存冲突 – 这通过使用’malloc’来分配适当大小的内存块来存储像素数据来解决.感谢Chuck Walbourn帮助我在黑暗中探索如何实际存储像素数据(默认情况下它实际上是32位/像素).仍然有可能/可能有些代码依靠运气来正确读取像素数据,但是它已经通过Chuck的输入进行了改进.

我的基本技术是;

> FindWindow在桌面上获取客户端窗口
> CreateCompatibleBitmap和SelectObject以及PrintWindow以获取快照的HBITMAP
> malloc为(byte *)像素缓冲区分配正确的空间量
> GetDIBits从HBITMAP填充(byte *)像素缓冲区
> CreateTexture2D构建纹理缓冲区
> CreateShaderResourceView将纹理映射到图形像素着色器

因此,使用代码截取Windows桌面窗口并将其作为纹理传递给direct3d应用程序是:

RECT user_window_rectangle;

HWND user_window = FindWindow(NULL,TEXT("Calculator"));    //the window can't be min
if (user_window == NULL)
{
    MessageBoxA(NULL,"Can't find Calculator","Camvas",MB_OK);
    return;
}
GetClientRect(user_window,&user_window_rectangle);
//create
HDC hdcScreen = GetDC(NULL);
HDC hdc = CreateCompatibleDC(hdcScreen);
UINT screenshot_width = user_window_rectangle.right - user_window_rectangle.left;
UINT screenshot_height = user_window_rectangle.bottom - user_window_rectangle.top;
hbmp = CreateCompatibleBitmap(hdcScreen,screenshot_height);

SelectObject(hdc,hbmp);

//Print to memory hdc
PrintWindow(user_window,PW_CLIENTONLY);

BITMAPINFOHEADER bmih;
ZeroMemory(&bmih,sizeof(BITMAPINFOHEADER));
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biWidth = screenshot_width;
bmih.biHeight = 0-screenshot_height;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;

int bytes_per_pixel = bmih.biBitCount / 8;

BYTE *pixels = (BYTE*)malloc(bytes_per_pixel * screenshot_width * screenshot_height);

BITMAPINFO bmi = { 0 };
bmi.bmiHeader = bmih;

int row_count = GetDIBits(hdc,hbmp,screenshot_height,pixels,&bmi,DIB_RGB_COLORS);

D3D11_TEXTURE2D_DESC screenshot_desc = CD3D11_TEXTURE2D_DESC(
    DXGI_FORMAT_B8G8R8A8_UNORM,// format
    screenshot_width,// width
    screenshot_height,// height
    1,// arraySize
    1,// mipLevels
    D3D11_BIND_SHADER_RESOURCE,// bindFlags
    D3D11_USAGE_DYNAMIC,// usage
    D3D11_CPU_ACCESS_WRITE,// cpuaccessFlags
    1,// sampleCount
    0,// sampleQuality
    0                               // miscFlags
    );

D3D11_SUBRESOURCE_DATA data;
ZeroMemory(&data,sizeof(D3D11_SUBRESOURCE_DATA));
data.pSysMem = pixels; // texArray; // &bmp.bmBits; //pixel buffer
data.SysMemPitch = bytes_per_pixel * screenshot_width;// line size in byte
data.SysMemSlicePitch = bytes_per_pixel * screenshot_width * screenshot_height;

hr = dev->CreateTexture2D(
    &screenshot_desc,// pixel buffer use to fill the texture
    &screenshot_texture  // created texture
    );

D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = screenshot_desc.Format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MostDetailedMip = screenshot_desc.MipLevels;

dev->CreateShaderResourceView(screenshot_texture,NULL,&shader_resource_view);

解决方法

主要问题是尝试直接使用& bmp.bmBits作为像素缓冲区导致图形驱动程序内存冲突 – 这通过使用’malloc’来分配适当大小的内存块来存储像素数据来解决.感谢Chuck Walbourn帮助我在黑暗中探索如何实际存储像素数据(默认情况下它实际上是32位/像素).仍然有可能/可能有些代码依靠运气来正确读取像素数据,但是它已经通过Chuck的输入进行了改进.

我的基本技术是;

> FindWindow在桌面上获取客户端窗口
> CreateCompatibleBitmap和SelectObject以及PrintWindow以获取快照的HBITMAP
> malloc为(byte *)像素缓冲区分配正确的空间量
> GetDIBits从HBITMAP填充(byte *)像素缓冲区
> CreateTexture2D构建纹理缓冲区
> CreateShaderResourceView将纹理映射到图形像素着色器

因此,&shader_resource_view);

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读