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>

PrintWindow 和 BitBlt

https://worktile.com/kb/p/6009

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: windows