【问题标题】:How can I get screenshot from all displays with X11?如何使用 X11 从所有显示器获取屏幕截图?
【发布时间】:2015-06-18 06:01:48
【问题描述】:

我正在写一个截图的东西,并发现了这个适用于 Mac 的优秀主题:How can I get screenshot from all displays on MAC?

我想知道是否有人拥有 x11 库的等价物?要获取所有监视器,然后将它们全部截屏?

我找到了这个话题:https://stackoverflow.com/a/5293559/1828637

但是对于像我这样的新手来说,从那里链接的代码并不容易理解。

RootWindow(3) 会得到所有显示器的总面积吗?然后我可以通过并获得显示器尺寸然后 XGetImage 那些部分就返回 RootWindow?

我遇到过这个话题:How do take a screenshot correctly with xlib? 但我不确定它是否支持多显示器。我在 ctypes 中执行此操作,因此如果不先完成繁重的编写任务,我就无法轻松测试该代码。所以我想知道这是否正确,或者我将如何修改它以处理多 mon?

编辑

那里的发帖人分享了他的代码,在这里可以看到:https://github.com/Lalaland/ScreenCap/blob/master/src/screenCapturerImpl.cpp#L96 但它很复杂,我不明白。它使用像XFixesGetCursorImage 这样的功能,我在文档中找不到这些功能,而且我看不到多显示器如何在那里工作。该主题的作者警告说他不记得代码,而且它可能不适用于现代 Linux。

【问题讨论】:

  • 根据您对 X 的配置方式(带或不带 Xinerama),您可能将其设置为多个根窗口或一个大窗口。如果很大:使用 XRandR 在该大窗口中获取视口位置,然后照常继续
  • 非常感谢@AndreySidorov,您能否为我指出通常部分的方向:)
  • 是的,只是 XGetImage 来抓取窗口的内容
  • 看看github.com/sidorares/node-x11/blob/master/examples/…,但不确定该示例是否有效
  • 它不只是在窗口上调用 XGetImage,而是从下到上遍历窗口树并在遍历时覆盖内容。不确定是否有必要,也许根窗口上的 GetImage 就足够了

标签: c screenshot x11


【解决方案1】:

这不是问题的完美答案,但可以修改以下代码以获得所需最终结果的非常快速的版本: https://github.com/Clodo76/vr-desktop-mirror/blob/master/DesktopCapture/main.cpp

DesktopCapturePlugin_Initialize 方法将所有显示转换为对象:

UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API DesktopCapturePlugin_Initialize()
{   
    DesksClean();

    g_needReinit = 0;


    IDXGIFactory1* factory;
    CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&factory));

    IDXGIAdapter1* adapter;
    for (int i = 0; (factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND); ++i)
    {
        IDXGIOutput* output;
        for (int j = 0; (adapter->EnumOutputs(j, &output) != DXGI_ERROR_NOT_FOUND); j++)
        {
            DXGI_OUTPUT_DESC outputDesc;
            output->GetDesc(&outputDesc);

            MONITORINFOEX monitorInfo;
            monitorInfo.cbSize = sizeof(MONITORINFOEX);
            GetMonitorInfo(outputDesc.Monitor, &monitorInfo);

            // Maybe in future add a function to identify the primary monitor.
            //if (monitorInfo.dwFlags == MONITORINFOF_PRIMARY)
            {
                int iDesk = DeskAdd();

                g_desks[iDesk].g_width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;                  
                g_desks[iDesk].g_height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;

                auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
                IDXGIOutput1* output1;
                output1 = reinterpret_cast<IDXGIOutput1*>(output);
                output1->DuplicateOutput(device, &g_desks[iDesk].g_deskDupl);
            }

            output->Release();
        }
        adapter->Release();
    }

    factory->Release();
}

然后 OnRenderEvent 方法将显示中的一帧复制到一个纹理中(本例中由 unity 提供):

void UNITY_INTERFACE_API OnRenderEvent(int eventId)
{
    for (int iDesk = 0; iDesk < g_nDesks; iDesk++)
    {
        if (g_desks[iDesk].g_deskDupl == nullptr || g_desks[iDesk].g_texture == nullptr)
        {
            g_needReinit++;
            return;
        }

        IDXGIResource* resource = nullptr;

        const UINT timeout = 0; // ms
        HRESULT resultAcquire = g_desks[iDesk].g_deskDupl->AcquireNextFrame(timeout, &g_desks[iDesk].g_frameInfo, &resource);
        if (resultAcquire != S_OK)
        {
            g_needReinit++;
            return;
        }

        g_desks[iDesk].g_isPointerVisible = (g_desks[iDesk].g_frameInfo.PointerPosition.Visible == TRUE);
        g_desks[iDesk].g_pointerX = g_desks[iDesk].g_frameInfo.PointerPosition.Position.x;
        g_desks[iDesk].g_pointerY = g_desks[iDesk].g_frameInfo.PointerPosition.Position.y;

        ID3D11Texture2D* texture;
        HRESULT resultQuery = resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&texture));
        resource->Release();

        if (resultQuery != S_OK)
        {
            g_needReinit++;
            return;
        }

        ID3D11DeviceContext* context;
        auto device = g_unity->Get<IUnityGraphicsD3D11>()->GetDevice();
        device->GetImmediateContext(&context);
        context->CopyResource(g_desks[iDesk].g_texture, texture);

        g_desks[iDesk].g_deskDupl->ReleaseFrame();
    }

    g_needReinit = 0;
}

【讨论】:

  • 谢谢,我已经解决了,我把代码挖出来分享一下。
猜你喜欢
  • 2016-01-03
  • 2016-12-11
  • 1970-01-01
  • 2012-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多