Gdk / X11 屏幕截图

blo*_*gsh 3 x11 gtk screen cairo gdk

我想编写一个程序来连续捕获屏幕并对图像进行一些修改。可以在以下位置找到完整的测试程序:

https://gist.github.com/blogsh/eb4dd4b96aca468c8bfa

但是,我遇到了一些问题。我做的第一个实验是使用 Gdk 根窗口,从中创建一个 Cairo 上下文,然后使用它的目标作为另一个窗口的源,其中的内容被绘制为:

mScreenContext = Gdk::Screen::get_default()->get_root_window()->create_cairo_context()
...
context->set_source(mScreenContext->get_target(), 0, 0);
context->paint();
Run Code Online (Sandbox Code Playgroud)

这工作得很好(上面源代码中的变体 1)。它只是将整个屏幕绘制到另一个窗口中。所以我的下一步是尝试将内容保存到 Cairo ImageSurface 中以便对其进行修改:

mImageContext->set_source(mScreenContext->get_target(), 0, 0);
mImageContext->paint();

context->set_source(mImageSurface, 0, 0);
context->paint();
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,对于 Gtk 窗口的第一次绘制,屏幕被捕获并绘制。不幸的是之后没有发生任何事情,仍然显示初始屏幕。如何解释这种行为?我必须承认我对这里的底层流程了解不多,所以也许有人可以提供一些提示?

使用的第三个变体Gdk::Pixbuf产生完全相同的行为:

mScreenBuffer = Gdk::Pixbuf::create(mGdkRootWindow, 0, 0, mScreenWidth, mScreenHeight);
Gdk::Cairo::set_source_pixbuf(context, mScreenBuffer, 0, 0);
context->paint();
Run Code Online (Sandbox Code Playgroud)

最后(变体 4)我尝试X11直接使用:

Display *display = XOpenDisplay((char*)0);
XImage *image = XGetImage(display, RootWindow(display, DefaultScreen(display)), 0, 0, mScreenWidth, mScreenHeight, AllPlanes, XYPixmap);

mScreenBuffer = Gdk::Pixbuf::create_from_data((const guint8*)image->data, Gdk::COLORSPACE_RGB, 0, 8, mScreenWidth, mScreenHeight, mScreenWidth);
Gdk::Cairo::set_source_pixbuf(context, mScreenBuffer, 0, 0);
context->paint();

XFree(image);
Run Code Online (Sandbox Code Playgroud)

实际上,这是有效的(尽管我还没有努力正确匹配像素格式),但是速度非常慢!

所以我很感激关于两个 Gdk 变体的问题是什么和/或如何加速 X11 方法的任何提示。或者也许有人知道一种完全不同的快速捕获屏幕的方法。

不幸的是,我对整个主题不太熟悉,但另一个想法是使用基于 OpenGL 的窗口管理器,在那里我可以直接读取帧缓冲区?那有意义吗?

该程序的主要思想是我有一台不能直接放在墙前的投影仪。所以我的想法是捕捉屏幕,做一些双线性变换来解决投影的偏斜,然后在另一个窗口中显示修改后的屏幕,这将在投影仪上显示......

小智 5

XShmGetImage 和 XShmPutImage 比 XGetImage 和 XPutImage 快。在下一个示例中,我创建了两个图像:src 和 dst。在每次迭代中,我在 src 中保存一个屏幕截图,然后在 dst 中渲染它的缩放版本。

下图显示了在名为“screencap”的窗口中运行的示例。在低需求时,它以 60 fps 的速度运行(如右上角的终端所示)。在高需求下,性能可能会下降到 25fps。

测试电脑:

Display resolution: 1920x1080
Graphic card: ATI Radeon HD 4200 (integrated)
CPU: AMD Phenom(tm) II X4 945, 3013.85 MHz
Window manager: XFCE 4.12 (compositing off)
Operating system: OpenBSD 5.9
Tested also in Linux (openSUSE Leap 42.1)
Run Code Online (Sandbox Code Playgroud)

屏幕截图运行

Display resolution: 1920x1080
Graphic card: ATI Radeon HD 4200 (integrated)
CPU: AMD Phenom(tm) II X4 945, 3013.85 MHz
Window manager: XFCE 4.12 (compositing off)
Operating system: OpenBSD 5.9
Tested also in Linux (openSUSE Leap 42.1)
Run Code Online (Sandbox Code Playgroud)

这只是一个例子。如果你喜欢它的表现,你应该考虑添加一个更好的合适的缩放算法并支持所有像素格式。

您可以像这样编译示例:

gcc screencap.c -o screencap -std=c99 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lXext -lm
Run Code Online (Sandbox Code Playgroud)

  • 我得到`screencap.c: In function 'timestamp': screencap.c:105:20: error: storage size of 'tz' is not known` (3认同)