windows 窗口采集和桌面采集的解决方案
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
前言
最近在研究windows截屏的功能从python的截屏方式
窗口截图(HWND)
-
PrintWindow 参考代码
-
QT的grabWindow 参考代码
-
winapi.BitBlt 参考代码
以上方法都无法抓取以下类的app图片(来自obs代码
-
chrome
-
Mozilla
-
XLMAIN /*excel */
-
PPTFrameClass /* powerpoint* /
-
OpusApp /* word */
-
ApplicationFrameWindow
-
windows.UI.Core.CoreWindow
而只能采用“桌面截图”的方式
桌面截图
- pyautogui.screenshot
- ImageGrab.grab
网上查找资料
windows 窗口采集
里面有详细的桌面截图介绍。
最终采用的方式
如果操作系统 > win10 1903 版本就使用wgc 方式
否则采用BitBlt
对于BitBlt 也无法截图的窗口则采用桌面截屏。
WGC使用方法
参考代码 Windows.UI.Composition-Win32-Samples
打开cpp/ScreenCaptureforHWND 下的工程编译就可以查看效果。
如何保存灰度图片
在代码SimpleCapture.cpp 中增加成员函数
static uint8_t *s_pix = nullptr;
static int s_slicePitch = 0;
void SimpleCapture::TakeSnapshot(winrt::com_ptr<ID3D11Texture2D> const& frame)
{
DirectX::ScratchImage im;
winrt::check_hresult(DirectX::CaptureTexture(GetDXGIInterfaceFromObject<ID3D11Device>(m_device).get(),
m_d3dContext.get(), frame.get(), im));
const auto& realImage = *im.GetImage(0, 0, 0);
// 图片格式BGRA8变灰度图
{
DirectX::Image copy_im = realImage;
copy_im.format = DXGI_FORMAT_R8_UNORM;
int pix = DirectX::BitsPerPixel(copy_im.format)/8;
copy_im.rowPitch = copy_im.width*pix;
copy_im.slicePitch = copy_im.rowPitch*copy_im.height;
if(s_slicePitch != copy_im.slicePitch)
{
if(s_pix)
{
delete []s_pix;
s_pix = nullptr;
}
s_pix = new uint8_t[copy_im.slicePitch];
s_slicePitch = copy_im.slicePitch;
}
copy_im.pixels = s_pix;
for(int i = 0,j = 0;i < copy_im.slicePitch;i++)
{
uint8_t b = realImage.pixels[j];
uint8_t g = realImage.pixels[j+1];
uint8_t r = realImage.pixels[j+2];
copy_im.pixels[i] = b;
j = j+4;
}
static int file_index = 0;
wchar_t buff[260] = {0};
swprintf(buff,260,L"output_%d.jpg",file_index);
winrt::check_hresult(DirectX::SaveToWICFile(copy_im, DirectX::WIC_FLAGS_NONE,
GUID_ContainerFormatJpeg, buff));
file_index++;
}
}
函数 OnFrameArrived中修改
{
auto frameSurface = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
winrt::com_ptr<ID3D11Texture2D> backBuffer;
winrt::check_hresult(m_swapChain->GetBuffer(0, winrt::guid_of<ID3D11Texture2D>(), backBuffer.put_void()));
m_d3dContext->CopyResource(backBuffer.get(), frameSurface.get());
// 每s保存一张不然app卡死
static DWORD s_last = 0;
if ((GetTickCount64() - s_last) > 1000) {
TakeSnapshot(frameSurface);
s_last = GetTickCount64();
}
}
SimpleCapture.cpp 修改头文件引入
#include <DirectXTex.h>
namespace winrt
{
using namespace winrt;
using namespace Windows;
using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::Graphics;
using namespace Windows::Graphics::Capture;
using namespace Windows::Graphics::DirectX;
using namespace Windows::Graphics::DirectX::Direct3D11;
using namespace Windows::Foundation::Numerics;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
}
最后在nuget包引入中修改packages.config 增加 directxtex_desktop_win10
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="directxtex_desktop_win10" version="2020.2.15.1" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.221121.5" targetFramework="native" />
</packages>